Commit 6b676a53 by Ivan Lan

Merge branch 'lan/basic_frame' into 'master'

Lan/basic frame See merge request !1
parents b172bf70 61fc8101
......@@ -7,6 +7,6 @@
/pkg/
/spec/reports/
/tmp/
/*.sqlite3
# rspec failure tracking
.rspec_status
......@@ -55,7 +55,7 @@ further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at liyijie825@gmail.com. All
reported by contacting the project team at mumumumushu@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
......
The MIT License (MIT)
Copyright (c) 2017 liyijie
Copyright (c) 2017 Ivan Lan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
......
......@@ -22,7 +22,10 @@ Or install it yourself as:
## Usage
TODO: Write usage instructions here
Create migration files as:
$ rake weather_model_engine:install:migrations
## Development
......
class CreateForecasts < ActiveRecord::Migration[5.0]
def up
create_table :forecasts do |t|
t.datetime :datetime
t.integer :temp_low
t.integer :temp_high
t.string :weather_text
t.string :weather_pic
t.string :cityname
t.string :win_dir
t.string :win_speed
t.timestamps
end
# 两个index 一起查询会不会导致其中一个作用几乎消失
# 需不需要按城市来分表
add_index :forecasts, :cityname
add_index :forecasts, :datetime
end
def down
drop_table :forecasts
end
end
require 'weather-model/version'
module WeatherModel
Dir[File.dirname(__FILE__) + '/weather-model/*.rb'].each { |file| require file }
require 'factory_girl_rails'
def self.included base
WeatherModel::SourceSchema.sorts.each { |sort| Object.const_set(sort, Module.new)}
WeatherModel::SourceSchema.constants.each do |source|
settings = SourceSchema.const_get(source)
Object.const_get(settings[:sort]).const_set("#{source.to_s.gsub('_', '::')}", Class.new(Storer::Mysql)).use_settings(settings)
end
end
end
module WeatherModel
require 'rails/engine'
class Engine < ::Rails::Engine
end
end
\ No newline at end of file
class Redic
def expire(key, ttl)
self.call("EXPIRE", key, ttl)
end
def ttl(key)
self.call("TTL", key)
end
end
\ No newline at end of file
module WeatherModel
module SourceSchema
def self.sorts
['Forecast']
end
ShanghaiTen = {
sort: 'Forecast',
table_name: :forecasts,
schema: {
datetime: :datetime,
cityname: :string,
temp_high: :string,
temp_low: :string,
weather_text: :string,
weather_pic: :string,
win_dir: :string,
win_speed: :string,
},
options: {
index: [:cityname],
expire: 1,
unique: :mysql_id,
father: nil,
son: nil,
},
factory_name: :forecast_shanghai_ten,
factory: {
datetime: '2017-05-16',
cityname: 'shanghai',
temp_high: '100',
temp_low: '0',
weather_text: '酷热严寒',
weather_pic: 'http://xxx.com',
win_dir: '东南西北风',
win_speed: '1级',
}
}
end
end
module WeatherModel
module Storer
require 'active_record'
require 'ohm'
require "ohm/expire"
class Mysql < ::ActiveRecord::Base
after_save :update_ohm
def self.use_settings settings
self.table_name = settings[:table_name]
define_ohm settings
define_factory settings
end
def self.define_ohm settings
const_set('Ohm', Class.new(SourceOhm)).use_settings(settings)
end
def self.define_factory settings
model_name = self
::FactoryGirl.define do
factory settings[:factory_name], class: model_name do
settings[:factory].each_pair{ |key, val| send(key, val) }
end
end
end
def get_ohm
self.class.const_get('Ohm')
end
class SourceOhm < ::Ohm::Model
include ::Ohm::Expire
def self.use_settings settings
attribute :mysql_id
attribute :updated_at
index :mysql_id
settings[:schema].keys.each { |attr|
attribute attr
}
[:index, :unique, :expire, :son, :dad].each do |option|
attrs = settings[:options][option]
attrs.is_a?(Array) ?
attrs.each{ |attr| method(option).call(attr) if attr } :
method(option).call(attrs) if attrs
end
end
# ohm-expire 只处理了create
# 而且 只把 attributes 的值给 TTL了。。。
def update attributes
obj = super(attributes)
obj.update_ttl self.class.instance_variable_get(:@expire)
end
def self.all
super.select{ |x| x.attributes.empty?}.map(&:delete)
super
end
private
def self.son his_son # input like :Post
# collection :posts, :Post
collection(his_son.to_s.underscore.pluralize.to_sym, his_son) if his_son && SourceSchema.const_defined?(his_son)
end
def self.dad his_dad # input like :Post
# reference :post, :Post
reference(his_dad.to_s.underscore.to_sym, his_dad ) if his_dad && SourceSchema.const_defined?(his_dad)
end
end
private
def update_ohm
ohm_attrs = self.attributes.except('created_at', 'id').merge(mysql_id: id)
# find 找不到 会自动生成
ohm_obj = get_ohm.find(mysql_id: id).first.try(:update, ohm_attrs) || get_ohm.create(ohm_attrs)
# rescue Ohm::UniqueIndexViolation mysql_id should be unique
end
end
end
end
module Weather
module Model
VERSION = "0.1.0"
end
module WeatherModel
VERSION = "0.1.0"
end
require "weather/model/version"
module Weather
module Model
# Your code goes here...
end
end
require "bundler/setup"
require "weather/model"
require "weather-model"
require 'rails'
require 'support/factory_girl'
RSpec.configure do |config|
# Enable flags like --only-failures and --next-failure
......
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
# RSpec without Rails
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
config.before(:suite) do
FactoryGirl.find_definitions
end
end
\ No newline at end of file
require "spec_helper"
require 'active_record'
require "ohm"
RSpec.describe WeatherModel do
include WeatherModel
before do
# start an ohm
Ohm.redis = Redic.new("redis://127.0.0.1:6379/5")
# run migration
Dir[File.dirname(__FILE__) + '/../db/migrate/*.rb'].each { |file| require file }
ActiveRecord::Base.establish_connection(
:adapter => 'sqlite3',
:database => 'weather-model-test.sqlite3'
)
ActiveRecord::Migration[5.0].subclasses.each do |migrate|
migrate.migrate(:up)
end
end
it "has a version number" do
expect(WeatherModel::VERSION).not_to be nil
end
describe 'test factory_girl' do
before do
@obj = create(:forecast_shanghai_ten)
end
it 'Test factory_girl' do
expect(@obj.class).to eq(Forecast::ShanghaiTen), 'factory_girl 生成成功'
end
end
it 'Forecast' do
@expire = 1
Forecast::ShanghaiTen::Ohm.expire @expire
mysql_obj = Forecast::ShanghaiTen.create({
datetime: '2017-05-16',
cityname: 'shanghai',
temp_high: '100',
temp_low: '0',
weather_text: '酷热严寒',
weather_pic: 'http://xxx.com',
win_dir: '东南西北风',
win_speed: '1级',
})
expect(Forecast::ShanghaiTen.count).to eq(1)
expect(Forecast::ShanghaiTen::Ohm.all.count).to eq(1)
expect(Forecast::ShanghaiTen::Ohm.all.first.temp_low).to eq(mysql_obj.temp_low.to_s)
expect(Forecast::ShanghaiTen::Ohm.all.first.get_ttl).to eq(@expire)
# 'ohm 对象 同步 mysql对象更新'
mysql_obj.update(temp_low: 99)
expect(Forecast::ShanghaiTen::Ohm.all.first.temp_low).to eq('99'), 'ohm 对象 同步 mysql对象更新'
sleep 1.5
expect(Forecast::ShanghaiTen::Ohm.all.count).to eq(0), 'TTL过期对象删除成功'
end
after do
ActiveRecord::Migration[5.0].subclasses.each do |migrate|
migrate.migrate(:down)
end
end
end
require "spec_helper"
RSpec.describe Weather::Model do
it "has a version number" do
expect(Weather::Model::VERSION).not_to be nil
end
it "does something useful" do
expect(false).to eq(true)
end
end
# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'weather/model/version'
require 'weather-model/version'
Gem::Specification.new do |spec|
spec.name = "weather-model"
spec.version = Weather::Model::VERSION
spec.authors = ["liyijie"]
spec.email = ["liyijie825@gmail.com"]
spec.version = WeatherModel::VERSION
spec.authors = ["Ivan Lan"]
spec.email = ["mumumumushu@gmail.com"]
spec.summary = %q{TODO: Write a short summary, because Rubygems requires one.}
spec.description = %q{TODO: Write a longer description or delete this line.}
spec.homepage = "TODO: Put your gem's website or public repo URL here."
spec.summary = %q{Weather Model}
spec.description = %q{Weather Model}
spec.homepage = "https://git.tallty.com/weather/weather-model"
spec.license = "MIT"
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
# to allow pushing to a single host or delete this section to allow pushing to any host.
if spec.respond_to?(:metadata)
spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
spec.metadata['allowed_push_host'] = "https://git.tallty.com/weather/weather-model"
else
raise "RubyGems 2.0 or newer is required to protect against " \
"public gem pushes."
......@@ -30,7 +30,19 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
# Object-Hash Mapping for Redis
# https://github.com/soveran/ohm
spec.add_dependency 'ohm'
# Ohm plugin that exposes ttl control over modules
# https://github.com/joseairosa/ohm-expire
spec.add_dependency 'ohm-expire'
spec.add_dependency 'activerecord'
spec.add_dependency 'factory_girl_rails'
spec.add_development_dependency "bundler", "~> 1.14"
spec.add_development_dependency "rake", "~> 10.0"
spec.add_development_dependency "rspec", "~> 3.0"
spec.add_development_dependency "sqlite3"
spec.add_development_dependency 'rspec-rails'
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment