rails_dictionary 0.2.3 → 0.3.pre.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG +4 -0
- data/Gemfile +1 -2
- data/{README.rdoc → README.v2.0.rdoc} +2 -5
- data/Rakefile +3 -2
- data/Readme.md +10 -0
- data/lib/rails_dictionary/models/active_record_extension.rb +21 -31
- data/lib/rails_dictionary/models/acts_as_dict_consumer.rb +77 -0
- data/lib/rails_dictionary/models/acts_as_dictionary.rb +9 -68
- data/lib/rails_dictionary/version.rb +1 -1
- data/lib/rails_dictionary.rb +28 -5
- data/lib/tasks/dicts.rake +11 -9
- data/rails_dictionary.gemspec +2 -1
- data/test/acts_as_consumer_test.rb +44 -0
- data/test/fake_app.rb +40 -0
- data/test/lookup_test.rb +39 -0
- data/test/rails_dictionary_test.rb +81 -0
- data/test/test_helper.rb +36 -0
- metadata +30 -16
- data/lib/rails_dictionary/array_core_ext.rb +0 -13
- data/lib/rails_dictionary/models/acts_as_dict_slave.rb +0 -88
- data/lib/rails_dictionary/models/acts_as_dict_type.rb +0 -56
- data/spec/fake_app.rb +0 -41
- data/spec/rails_dictionary_spec.rb +0 -122
- data/spec/spec_helper.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 309d2e3ca49c9e564523d61307014d44987b7561
|
4
|
+
data.tar.gz: e6ea71c9fc377893c23883a0a0f08d001bc2f328
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0daca999ef3ad0ff8888e5e2ca7ae85fe81bbc62c5e1a7c696f51f7d904eeb5bb985200a471306efb75f5c4ce3e599b5cd2e57513f07ef7d1a95f26294b0acef
|
7
|
+
data.tar.gz: 987fdd01ad2d98bb9a211eda4aed92cedbe9469f4cfaf7a1d6b6803a52f41315ba9c4239e43826a620fb7d289fcc9c53dd206942db0f6f60ccd25ebe206f9d54
|
data/CHANGELOG
CHANGED
data/Gemfile
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
= Plan
|
2
|
-
Working on sti branch will target to 0.3 version which will not compatible with 0.1 and 0.2
|
3
|
-
|
4
1
|
= Intro
|
5
2
|
There are always some static data(not static page) in application.For example product type or student diploma type.
|
6
3
|
|
@@ -29,7 +26,7 @@ See change log for brief info.
|
|
29
26
|
== Sample
|
30
27
|
Run following task will give you a simple start.Maybe you should try it in a new application first.
|
31
28
|
rake dicts:generate
|
32
|
-
rake dicts:
|
29
|
+
rake dicts:sample_consumer
|
33
30
|
rake db:migrate
|
34
31
|
rake dicts:sample_data
|
35
32
|
These task are just generate table dictionaries,dict_types,students and some sample data.The data should be
|
@@ -80,7 +77,7 @@ Here is what should be like.Student model can be other models.
|
|
80
77
|
end
|
81
78
|
|
82
79
|
class Student < ActiveRecord::Base
|
83
|
-
# use
|
80
|
+
# use acts_as_dict_consumer when your rails_dictionary version < 0.2
|
84
81
|
acts_as_dict_consumer
|
85
82
|
end
|
86
83
|
|
data/Rakefile
CHANGED
@@ -5,6 +5,7 @@ task :default => [:test]
|
|
5
5
|
|
6
6
|
desc "Running Test"
|
7
7
|
task :test do
|
8
|
-
|
9
|
-
system
|
8
|
+
system 'ruby test/rails_dictionary_test.rb'
|
9
|
+
system 'ruby test/acts_as_consumer_test.rb'
|
10
|
+
system 'ruby test/lookup_test.rb'
|
10
11
|
end
|
data/Readme.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
## Usage
|
2
|
+
|
3
|
+
Version 0.3 is not backward compatible!!
|
4
|
+
Only for version 0.3.
|
5
|
+
|
6
|
+
See [README.rdoc](https://github.com/raykin/rails_dictionary/blob/sti/README.v2.0.rdoc) for version 0.2.
|
7
|
+
|
8
|
+
### Changes from 0.2 to 0.3
|
9
|
+
|
10
|
+
Locale feature removed. Please use i18n.
|
@@ -5,44 +5,34 @@ module RailsDictionary
|
|
5
5
|
end
|
6
6
|
|
7
7
|
module ClassMethods
|
8
|
-
# TODO: move macro define in each module file
|
9
|
-
# See Usage in readme.doc.
|
10
|
-
def acts_as_dict_type
|
11
|
-
|
12
|
-
has_many :dictionaries
|
13
|
-
validates_uniqueness_of :name
|
14
|
-
after_save :delete_all_caches
|
15
|
-
after_destroy :delete_all_caches
|
16
|
-
|
17
|
-
include RailsDictionary::ActsAsDictType
|
18
|
-
end
|
19
8
|
|
20
9
|
def acts_as_dictionary
|
21
|
-
|
22
|
-
|
23
|
-
after_save :delete_dicts_cache
|
24
|
-
after_destroy :delete_dicts_cache
|
25
|
-
scope :dict_type_name_eq, lambda { |name| joins(:dict_type).where("dict_types.name" => name) }
|
26
|
-
|
27
|
-
include RailsDictionary::ActsAsDictionary
|
10
|
+
include ActsAsDictionary
|
11
|
+
validates_uniqueness_of :name, scope: [inheritance_column]
|
28
12
|
end
|
29
13
|
|
30
|
-
# Ex:
|
31
|
-
#
|
32
|
-
# :
|
33
|
-
# :
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
14
|
+
# Ex: acts_as_dict_consumer on: :city
|
15
|
+
#
|
16
|
+
# on: - add dict mapping columns, can be string or array of string
|
17
|
+
# relation_type: - belongs_to/many_to_many, default is belongs_to. has_many Not supported yet
|
18
|
+
# class_name: - Dictionary class name
|
19
|
+
# locale: - add and initialize class attribute default_dict_locale
|
20
|
+
def acts_as_dict_consumer(opts={})
|
21
|
+
include ActsAsDictConsumer
|
22
|
+
case opts[:on]
|
23
|
+
when Array
|
24
|
+
opts[:on].each do |on_value|
|
25
|
+
build_dict_relation(opts.merge(on: on_value))
|
26
|
+
end
|
27
|
+
when String, Symbol
|
28
|
+
build_dict_relation(opts)
|
29
|
+
else
|
30
|
+
raise TypeError, 'Wrong value of params on'
|
42
31
|
end
|
43
32
|
end
|
44
33
|
|
45
|
-
alias_method :acts_as_dict_consumer, :acts_as_dict_slave
|
46
34
|
end
|
47
35
|
end
|
48
36
|
end
|
37
|
+
|
38
|
+
::ActiveRecord::Base.send :include, RailsDictionary::ActiveRecordExtension
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module RailsDictionary
|
2
|
+
module ActsAsDictConsumer
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
|
9
|
+
# Generate dynamic instance method named_column to consumer model
|
10
|
+
# def named_city(locale=nil)
|
11
|
+
# locale = locale.presence || default_dict_locale.presence || :en
|
12
|
+
# locale = "name_#{locale}"
|
13
|
+
# self.send(city_dict).try(:send,locale)
|
14
|
+
# end
|
15
|
+
# alias_method :city_name, :named_city
|
16
|
+
# def named_dict_value(method_name)
|
17
|
+
# belongs_to_name="#{method_name}_dict".to_sym
|
18
|
+
# origin_method_name = method_name
|
19
|
+
# method_name="named_#{method_name}"
|
20
|
+
# define_method(method_name) do | locale=nil |
|
21
|
+
# locale = locale.presence || default_dict_locale.presence || :en
|
22
|
+
# locale = "name_#{locale}"
|
23
|
+
# self.send(belongs_to_name).try(:send,locale)
|
24
|
+
# end
|
25
|
+
# alias_method "#{origin_method_name}_name".to_sym, method_name.to_sym
|
26
|
+
# end
|
27
|
+
|
28
|
+
# Build dynamic method column_name= to the consumer model
|
29
|
+
#
|
30
|
+
# ex:
|
31
|
+
# def city_name=(value, options = {})
|
32
|
+
# send "city=", dictionary_obj
|
33
|
+
# end
|
34
|
+
def dict_name_equal
|
35
|
+
relation_name = @dict_relation_name
|
36
|
+
relation_type = @dict_relation_type
|
37
|
+
method_name = "#{relation_name}_name="
|
38
|
+
class_opt = @opt
|
39
|
+
define_method(method_name) do |value, options={}|
|
40
|
+
dicts = RailsDictionary.dclass.where(name: Array(value), type: class_opt[:class_name])
|
41
|
+
if dicts
|
42
|
+
if relation_type == :belongs_to
|
43
|
+
send "#{relation_name}=", dicts.first
|
44
|
+
elsif relation_type == :many_to_many
|
45
|
+
send "#{relation_name}=", dicts.map(&:id)
|
46
|
+
else
|
47
|
+
raise "Wrong relation method name: #{relation_type}"
|
48
|
+
end
|
49
|
+
else
|
50
|
+
# do nothing ?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# dont think instance var is a good sollution
|
56
|
+
# cause the consumer class will include other lib too
|
57
|
+
def build_dict_relation(opt)
|
58
|
+
@opt = opt
|
59
|
+
@dict_relation_name = @opt.delete :on
|
60
|
+
raise 'params on cant be nil' if @dict_relation_name.nil?
|
61
|
+
@dict_relation_type = @opt.delete(:relation_type) || :belongs_to
|
62
|
+
# @opt[:foreign_key] ||= "#{@dict_relation_name}_id"
|
63
|
+
@opt[:class_name] ||= "#{RailsDictionary.config.dictionary_klass}::#{@dict_relation_name.to_s.singularize.camelize}"
|
64
|
+
::RailsDictionary.init_dict_sti_class(@opt[:class_name])
|
65
|
+
if @dict_relation_type.to_sym == :belongs_to
|
66
|
+
send @dict_relation_type, @dict_relation_name, @opt
|
67
|
+
elsif @dict_relation_type.to_sym == :many_to_many
|
68
|
+
# no code required?
|
69
|
+
# build_many_to_many_dict_relation
|
70
|
+
end
|
71
|
+
dict_name_equal
|
72
|
+
end
|
73
|
+
|
74
|
+
end # END ClassMethods
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -2,83 +2,24 @@ module RailsDictionary
|
|
2
2
|
module ActsAsDictionary
|
3
3
|
def self.included(base)
|
4
4
|
base.extend(ClassMethods)
|
5
|
-
base.send :include,InstanceMethods
|
5
|
+
base.send :include, InstanceMethods
|
6
6
|
end
|
7
7
|
|
8
8
|
module ClassMethods
|
9
9
|
|
10
|
-
#
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
# Dictionary.student_city(:locale => :zh) - a select format array which can be used
|
16
|
-
# in view method select as choice params
|
17
|
-
# Programmer DOC && TODO:
|
18
|
-
# rethink about the cache.
|
19
|
-
# cache methods like Dictionary.student_city(:locale => :zh,:sort => :name_fr)
|
20
|
-
# but not cache Dictionary.student_city, return it as relation
|
21
|
-
#
|
22
|
-
# Remove nil noise,if listed_attr =[[nil, 201], [nil, 203], [nil, 202], ["Sciences", 200]]
|
23
|
-
# the sort would be failed of ArgumentError: comparison of Array with Array failed
|
24
|
-
# split this method ,make it more short and maintainance
|
25
|
-
def method_missing(method_id,options={})
|
26
|
-
if DictType.all_types.include? method_id
|
27
|
-
method_name=method_id.to_s.downcase
|
28
|
-
# TODO: If cache engine is failed, then the code will failed with null cant dup
|
29
|
-
Rails.cache.fetch("Dictionary.#{method_name}") { dict_type_name_eq(method_name).to_a }
|
30
|
-
listed_attr=Rails.cache.read("Dictionary.#{method_name}").dup # Instance of ActiveRecord::Relation can not be dup?
|
31
|
-
build_scope_method(method_id)
|
32
|
-
if options.keys.include? :locale or options.keys.include? "locale"
|
33
|
-
locale="name_#{ options[:locale] }"
|
34
|
-
sort_block=sort_dicts(options)
|
35
|
-
listed_attr.sort!(&sort_block) if sort_block
|
36
|
-
listed_attr.map! { |a| [a.send(locale),a.id] }.reject! {|ele| ele.first.nil?}
|
37
|
-
end
|
38
|
-
listed_attr
|
39
|
-
else
|
40
|
-
super
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# Override this method to get customed sort block
|
45
|
-
def sort_dicts(options)
|
46
|
-
if options.keys.include? :locale or options.keys.include? "locale"
|
47
|
-
locale="name_#{ options[:locale] }"
|
48
|
-
if options[:locale].to_sym == :zh
|
49
|
-
Proc.new { |a,b| a.send(locale).encode('GBK') <=> b.send(locale).encode('GBK') }
|
50
|
-
else
|
51
|
-
Proc.new { |a,b| a.send(locale).downcase <=> b.send(locale).downcase }
|
52
|
-
end
|
53
|
-
else
|
54
|
-
false
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def respond_to?(name, include_private=false)
|
59
|
-
DictType.all_types.include?(name) || super
|
60
|
-
end
|
61
|
-
|
62
|
-
private
|
63
|
-
|
64
|
-
def build_scope_method(name)
|
65
|
-
scope_method_name = "scoped_#{name}".to_sym
|
66
|
-
unless respond_to? scope_method_name
|
67
|
-
define_singleton_method scope_method_name do
|
68
|
-
# see http://stackoverflow.com/questions/18198963/with-rails-4-model-scoped-is-deprecated-but-model-all-cant-replace-it
|
69
|
-
# for usage of where(nil)
|
70
|
-
dict_type_name_eq(name).where(nil)
|
71
|
-
end
|
72
|
-
end
|
10
|
+
# override to make sure STI class init first
|
11
|
+
def new(opts)
|
12
|
+
type_opt = opts.with_indifferent_access[inheritance_column]
|
13
|
+
RailsDictionary.init_dict_sti_class(type_opt) if type_opt
|
14
|
+
super
|
73
15
|
end
|
74
16
|
|
75
17
|
end # End ClassMethods
|
76
18
|
|
77
19
|
module InstanceMethods
|
78
|
-
def
|
79
|
-
|
80
|
-
|
81
|
-
return true
|
20
|
+
def type=(name)
|
21
|
+
::RailsDictionary.init_dict_sti_class(name)
|
22
|
+
super
|
82
23
|
end
|
83
24
|
end # End InstanceMethods
|
84
25
|
|
data/lib/rails_dictionary.rb
CHANGED
@@ -1,10 +1,33 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), "rails_dictionary/array_core_ext")
|
2
1
|
require File.join(File.dirname(__FILE__), "rails_dictionary/models/active_record_extension")
|
3
|
-
require File.join(File.dirname(__FILE__), "rails_dictionary/models/acts_as_dict_type")
|
4
2
|
require File.join(File.dirname(__FILE__), "rails_dictionary/models/acts_as_dictionary")
|
5
|
-
require File.join(File.dirname(__FILE__), "rails_dictionary/models/
|
3
|
+
require File.join(File.dirname(__FILE__), "rails_dictionary/models/acts_as_dict_consumer")
|
6
4
|
|
7
5
|
# rake tasks not autoload in Rails4
|
8
|
-
|
6
|
+
# todo: may add migration(from 0.2 to 0.3) task
|
7
|
+
# Dir[File.expand_path('../tasks/**/*.rake',__FILE__)].each { |ext| load ext } if defined?(Rake)
|
9
8
|
|
10
|
-
|
9
|
+
module RailsDictionary
|
10
|
+
|
11
|
+
def self.config
|
12
|
+
Config.instance
|
13
|
+
end
|
14
|
+
|
15
|
+
class Config < Struct.new(:dictionary_klass, :defined_sti_klass)
|
16
|
+
include Singleton
|
17
|
+
end
|
18
|
+
|
19
|
+
config.dictionary_klass = :Dictionary
|
20
|
+
config.defined_sti_klass = []
|
21
|
+
|
22
|
+
def self.dclass
|
23
|
+
@dclass ||= config.dictionary_klass.to_s.constantize
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.init_dict_sti_class(klass)
|
27
|
+
unless config.defined_sti_klass.include?(klass) || Module.const_defined?(klass)
|
28
|
+
subklass = klass.sub "#{config.dictionary_klass}::", ''
|
29
|
+
dclass.const_set subklass, Class.new(dclass)
|
30
|
+
config.defined_sti_klass.push(klass)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/tasks/dicts.rake
CHANGED
@@ -2,20 +2,22 @@
|
|
2
2
|
namespace :dicts do
|
3
3
|
desc "Generate dictionary and dict_type model"
|
4
4
|
task :generate do
|
5
|
-
system "rails g model dictionary name_en
|
6
|
-
system "rails g model dict_type name:string"
|
5
|
+
system "rails g model dictionary name_en name_zh name_fr type"
|
7
6
|
end
|
7
|
+
|
8
8
|
desc "Generate student model"
|
9
|
-
task :
|
9
|
+
task :sample_consumer do
|
10
10
|
system "rails g model student email:string city:integer school:integer"
|
11
11
|
end
|
12
|
+
|
12
13
|
desc "Generate sample data for rails_dictionary gem"
|
13
14
|
task :sample_data => [:environment] do
|
14
|
-
@dt_stu_city=DictType.create! :
|
15
|
-
@dt_stu_school=DictType.create! :
|
16
|
-
@dy_shanghai=Dictionary.create! name_en: "shanghai",name_zh: "上海",name_fr: "shanghai",dict_type_id: @dt_stu_city.id
|
17
|
-
@dy_beijing=Dictionary.create! name_en: "beijing",name_zh: "北京",name_fr: "Pékin",dict_type_id: @dt_stu_city.id
|
18
|
-
@stu_beijing=Student.create! email: "beijing@dict.com",city: @dy_beijing.id
|
19
|
-
@stu_shanghai=Student.create! email: "shanghai@dict.com",city: @dy_shanghai.id
|
15
|
+
# @dt_stu_city=DictType.create! name: "student_city"
|
16
|
+
# @dt_stu_school=DictType.create! name: "student_school"
|
17
|
+
@dy_shanghai=Dictionary.create! name_en: "shanghai", name_zh: "上海", name_fr: "shanghai", dict_type_id: @dt_stu_city.id
|
18
|
+
@dy_beijing=Dictionary.create! name_en: "beijing", name_zh: "北京", name_fr: "Pékin", dict_type_id: @dt_stu_city.id
|
19
|
+
@stu_beijing=Student.create! email: "beijing@dict.com", city: @dy_beijing.id
|
20
|
+
@stu_shanghai=Student.create! email: "shanghai@dict.com", city: @dy_shanghai.id
|
20
21
|
end
|
22
|
+
|
21
23
|
end
|
data/rails_dictionary.gemspec
CHANGED
@@ -14,9 +14,10 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.rubyforge_project = "rails_dictionary"
|
15
15
|
|
16
16
|
s.add_runtime_dependency 'rails', '> 4.0'
|
17
|
+
s.add_runtime_dependency 'database_cleaner'
|
17
18
|
|
18
19
|
s.files = `git ls-files`.split("\n")
|
19
|
-
s.test_files = `git ls-files -- {test
|
20
|
+
s.test_files = `git ls-files -- {test}/*`.split("\n")
|
20
21
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
22
|
s.require_paths = ["lib"]
|
22
23
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.expand_path('test_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
class TestConsumer < TestSupporter
|
4
|
+
|
5
|
+
end
|
6
|
+
|
7
|
+
class TestConsumeOneColumn < TestConsumer
|
8
|
+
def setup
|
9
|
+
super
|
10
|
+
Student.acts_as_dict_consumer on: :city
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_student_should_has_method_city
|
14
|
+
assert Student.new.respond_to?(:city), 'student should has method city'
|
15
|
+
assert Student.new.respond_to?(:create_city), 'student should has method create_city'
|
16
|
+
assert_includes RailsDictionary.config.defined_sti_klass, 'Dictionary::City'
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_dictionary_city_class_exist
|
20
|
+
assert Dictionary.const_defined?('City'), 'Dictionary::City should be defined'
|
21
|
+
assert_includes RailsDictionary.config.defined_sti_klass, 'Dictionary::City'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class TestConsumeMultipleColumns < TestConsumer
|
26
|
+
|
27
|
+
def setup
|
28
|
+
super
|
29
|
+
Student.acts_as_dict_consumer on: [:city, :school]
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_student_should_has_method_city
|
33
|
+
assert Student.new.respond_to?(:city), 'student should has method city'
|
34
|
+
assert Student.new.respond_to?(:create_city), 'student should has method create_city'
|
35
|
+
assert Student.new.respond_to?(:school), 'student should has method city'
|
36
|
+
assert Student.new.respond_to?(:create_school), 'student should has method city'
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_dictionary_city_and_schoold_exist
|
40
|
+
assert Dictionary.const_defined?('City'), 'Dictionary::City should be defined'
|
41
|
+
assert Dictionary.const_defined?('School'), 'Dictionary::City should be defined'
|
42
|
+
assert_equal(['Dictionary::City', 'Dictionary::School'], RailsDictionary.config.defined_sti_klass)
|
43
|
+
end
|
44
|
+
end
|
data/test/fake_app.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# database
|
2
|
+
ActiveRecord::Base.configurations = {'test' => {:adapter => 'sqlite3', :database => ':memory:'}}
|
3
|
+
ActiveRecord::Base.establish_connection(:test)
|
4
|
+
|
5
|
+
# config
|
6
|
+
app = Class.new(Rails::Application)
|
7
|
+
app.config.active_support.deprecation = :log
|
8
|
+
app.config.eager_load = false
|
9
|
+
app.initialize!
|
10
|
+
|
11
|
+
class Dictionary < ActiveRecord::Base
|
12
|
+
acts_as_dictionary
|
13
|
+
end
|
14
|
+
|
15
|
+
class Student < ActiveRecord::Base
|
16
|
+
end
|
17
|
+
|
18
|
+
class Lookup < ActiveRecord::Base
|
19
|
+
end
|
20
|
+
|
21
|
+
#migrations
|
22
|
+
class CreateAllTables < ActiveRecord::Migration
|
23
|
+
def self.up
|
24
|
+
create_table(:dictionaries) {|t| t.string :name; t.string :type}
|
25
|
+
create_table(:students) do |t|
|
26
|
+
t.string :email
|
27
|
+
t.integer :city_id
|
28
|
+
t.integer :school_id
|
29
|
+
t.text :major_array
|
30
|
+
t.text :majors
|
31
|
+
end
|
32
|
+
create_table(:lookups) { |t| t.string :name; t.string :type }
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.down
|
36
|
+
drop_table :dictionaries
|
37
|
+
drop_table :students
|
38
|
+
drop_table :lookups
|
39
|
+
end
|
40
|
+
end
|
data/test/lookup_test.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.expand_path('test_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module TestLookup
|
4
|
+
|
5
|
+
class TestAsDictionary < TestSupporter
|
6
|
+
|
7
|
+
def prepare_data
|
8
|
+
@art = Lookup.create!(name: 'art', type: 'Lookup::Major')
|
9
|
+
@math = Lookup.create!(name: 'math', type: 'Lookup::Major')
|
10
|
+
end
|
11
|
+
|
12
|
+
def setup
|
13
|
+
RailsDictionary.config.dictionary_klass = :Lookup
|
14
|
+
Lookup.acts_as_dictionary
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_lookup
|
19
|
+
prepare_data
|
20
|
+
assert Lookup, Lookup::Major.superclass
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_student_major_array
|
24
|
+
Student.acts_as_dict_consumer on: :major_array, relation_type: :many_to_many, class_name: 'Lookup::Major'
|
25
|
+
prepare_data
|
26
|
+
s = Student.new(major_array_name: ['art', 'math'])
|
27
|
+
s.save!; s.reload
|
28
|
+
assert_equal([@art.id, @math.id], s.major_array)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_student_with_majors
|
32
|
+
Student.acts_as_dict_consumer on: :majors, relation_type: :many_to_many
|
33
|
+
prepare_data
|
34
|
+
s = Student.new(majors_name: ['art', 'math'])
|
35
|
+
s.save!; s.reload
|
36
|
+
assert_equal([@art.id, @math.id], s.majors)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require File.expand_path('test_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
class TestRailsDictionary < TestSupporter
|
4
|
+
|
5
|
+
class TestActiveRecordExtension < TestRailsDictionary
|
6
|
+
[:acts_as_dictionary, :acts_as_dict_consumer].each do |method_name|
|
7
|
+
define_method "test_#{method_name}_exists_ar" do
|
8
|
+
assert_includes ActiveRecord::Base.methods, method_name
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class PreTestDatabase < TestRailsDictionary
|
14
|
+
|
15
|
+
def test_no_dictionary_data_exist_before
|
16
|
+
assert_equal 0, Dictionary.count, 'dicionaries table should be blank'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class TestInitSubDictClass < TestRailsDictionary
|
21
|
+
def setup
|
22
|
+
super
|
23
|
+
if Dictionary.const_defined? 'City'
|
24
|
+
Dictionary.send :remove_const, 'City'
|
25
|
+
RailsDictionary.config.defined_sti_klass.delete('Dictionary::City')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_dictionary_city_class_when_create_dictionary
|
30
|
+
@shanghai = Dictionary.create!(name: "shanghai", type: 'Dictionary::City')
|
31
|
+
assert Dictionary, Dictionary::City.superclass
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_dictionary_city_class_when_assign_type
|
35
|
+
beijing = Dictionary.new(name: 'beijing')
|
36
|
+
beijing.type = 'Dictionary::City'
|
37
|
+
beijing.save!
|
38
|
+
assert Dictionary, Dictionary::City.superclass
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_dictionary_city_class_when_assign_type_in_new
|
42
|
+
beijing = Dictionary.new(name: 'beijing', type: 'Dictionary::City')
|
43
|
+
beijing.save!
|
44
|
+
assert Dictionary, Dictionary::City.superclass
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class TestWithDB < TestRailsDictionary
|
51
|
+
def setup
|
52
|
+
super
|
53
|
+
Dictionary.acts_as_dictionary
|
54
|
+
@beijing, @shanghai = prepare_city_data
|
55
|
+
|
56
|
+
@stu_beijing = Student.create! email: "beijing@dict.com", city_id: @shanghai.id
|
57
|
+
@stu_shanghai = Student.create! email: "shanghai@dict.com", city_id: @shanghai.id
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class TestStudent < TestWithDB
|
62
|
+
def setup
|
63
|
+
super
|
64
|
+
Student.acts_as_dict_consumer on: [:city]
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_city_name_equal_to_exist_dictionary_name
|
68
|
+
assert_equal 1, Dictionary.where(name: "beijing").count
|
69
|
+
@stu_shanghai.update_attributes city_name: "beijing"
|
70
|
+
assert_equal 'beijing', @stu_shanghai.reload.city.name
|
71
|
+
assert_equal 1, Dictionary.where(name: "beijing").count
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_a_student_with_shanghai_city
|
75
|
+
s = Student.create(city_name: "shanghai")
|
76
|
+
s.reload
|
77
|
+
s.city.name.should == "shanghai"
|
78
|
+
assert_equal Dictionary.find_by(name: 'shanghai').id, s.city_id
|
79
|
+
assert_equal 1, Dictionary.where(name: "shanghai").count
|
80
|
+
end
|
81
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# copy and modify the test design of kaminari(a paginate gem for Rails3)
|
2
|
+
RAILS_ENV = 'test'
|
3
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
4
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
5
|
+
require 'byebug'
|
6
|
+
require 'rack/test'
|
7
|
+
require 'rails'
|
8
|
+
require 'active_record'
|
9
|
+
require 'rails_dictionary'
|
10
|
+
|
11
|
+
ActiveRecord::Migration.verbose = false
|
12
|
+
|
13
|
+
require File.join(File.dirname(__FILE__), 'fake_app')
|
14
|
+
|
15
|
+
CreateAllTables.up unless ActiveRecord::Base.connection.table_exists? 'dictionaries'
|
16
|
+
|
17
|
+
Student.serialize :major_array, Array
|
18
|
+
Student.serialize :majors, Array
|
19
|
+
|
20
|
+
require 'minitest/autorun'
|
21
|
+
require 'database_cleaner'
|
22
|
+
|
23
|
+
DatabaseCleaner.strategy = :truncation
|
24
|
+
|
25
|
+
class TestSupporter < Minitest::Test
|
26
|
+
def setup
|
27
|
+
DatabaseCleaner.clean
|
28
|
+
end
|
29
|
+
|
30
|
+
def prepare_city_data
|
31
|
+
[
|
32
|
+
Dictionary.create!(name: 'beijing', type: 'Dictionary::City'),
|
33
|
+
Dictionary.create!(name: 'shanghai', type: 'Dictionary::City')
|
34
|
+
]
|
35
|
+
end
|
36
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_dictionary
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.pre.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Raykin Lee
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-03-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '4.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: database_cleaner
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
description: Rails plugin for mapping static data of web application to Dictionary
|
28
42
|
class
|
29
43
|
email:
|
@@ -35,20 +49,21 @@ files:
|
|
35
49
|
- ".gitignore"
|
36
50
|
- CHANGELOG
|
37
51
|
- Gemfile
|
38
|
-
- README.rdoc
|
52
|
+
- README.v2.0.rdoc
|
39
53
|
- Rakefile
|
54
|
+
- Readme.md
|
40
55
|
- lib/rails_dictionary.rb
|
41
|
-
- lib/rails_dictionary/array_core_ext.rb
|
42
56
|
- lib/rails_dictionary/models/active_record_extension.rb
|
43
|
-
- lib/rails_dictionary/models/
|
44
|
-
- lib/rails_dictionary/models/acts_as_dict_type.rb
|
57
|
+
- lib/rails_dictionary/models/acts_as_dict_consumer.rb
|
45
58
|
- lib/rails_dictionary/models/acts_as_dictionary.rb
|
46
59
|
- lib/rails_dictionary/version.rb
|
47
60
|
- lib/tasks/dicts.rake
|
48
61
|
- rails_dictionary.gemspec
|
49
|
-
-
|
50
|
-
-
|
51
|
-
-
|
62
|
+
- test/acts_as_consumer_test.rb
|
63
|
+
- test/fake_app.rb
|
64
|
+
- test/lookup_test.rb
|
65
|
+
- test/rails_dictionary_test.rb
|
66
|
+
- test/test_helper.rb
|
52
67
|
homepage: https://github.com/raykin/rails_dictionary
|
53
68
|
licenses: []
|
54
69
|
metadata: {}
|
@@ -63,15 +78,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
63
78
|
version: '0'
|
64
79
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
80
|
requirements:
|
66
|
-
- - "
|
81
|
+
- - ">"
|
67
82
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
83
|
+
version: 1.3.1
|
69
84
|
requirements: []
|
70
|
-
|
85
|
+
rubyforge_project: rails_dictionary
|
86
|
+
rubygems_version: 2.2.2
|
71
87
|
signing_key:
|
72
88
|
specification_version: 4
|
73
89
|
summary: dictionary data for web application
|
74
|
-
test_files:
|
75
|
-
|
76
|
-
- spec/rails_dictionary_spec.rb
|
77
|
-
- spec/spec_helper.rb
|
90
|
+
test_files: []
|
91
|
+
has_rdoc:
|
@@ -1,13 +0,0 @@
|
|
1
|
-
class Array
|
2
|
-
# Return a hash by compare two arrays
|
3
|
-
def extract_to_hash(keys_array)
|
4
|
-
ret_hash={}
|
5
|
-
keys_array.each {|ky| ret_hash[ky.to_sym]=[]}
|
6
|
-
self.each do |sf|
|
7
|
-
keys_array.each do |ky|
|
8
|
-
ret_hash[ky.to_sym] << sf.sub("#{ky}_","") if sf =~ Regexp.new("^#{ky}_")
|
9
|
-
end
|
10
|
-
end
|
11
|
-
ret_hash.reject { |k,v| v.blank? }
|
12
|
-
end
|
13
|
-
end
|
@@ -1,88 +0,0 @@
|
|
1
|
-
module RailsDictionary
|
2
|
-
module ActsAsDictSlave
|
3
|
-
def self.included(base)
|
4
|
-
base.extend(ClassMethods)
|
5
|
-
end
|
6
|
-
|
7
|
-
module ClassMethods
|
8
|
-
|
9
|
-
# return columns that exist in DictType#tab_and_column
|
10
|
-
def columns_in_dict_type
|
11
|
-
if ActiveRecord::VERSION::STRING < '3.1'
|
12
|
-
DictType.tab_and_column[self.name.underscore.to_sym]
|
13
|
-
elsif DictType.table_exists?
|
14
|
-
DictType.tab_and_column[self.name.underscore.to_sym]
|
15
|
-
else
|
16
|
-
[]
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# columns which map to dictionary
|
21
|
-
def dict_columns(ops={})
|
22
|
-
conf = { except: nil, add: nil}
|
23
|
-
conf.update(ops)
|
24
|
-
cidt = columns_in_dict_type || []
|
25
|
-
cidt.delete(conf[:except])
|
26
|
-
case conf[:add]
|
27
|
-
when String
|
28
|
-
cidt.push(conf[:add])
|
29
|
-
when Array
|
30
|
-
cidt.push(*conf[:add])
|
31
|
-
else nil
|
32
|
-
end
|
33
|
-
cidt.uniq! || cidt
|
34
|
-
end
|
35
|
-
|
36
|
-
# add a belongs_to(Dictionary) association and a named_{column} method
|
37
|
-
def add_dynamic_column_method
|
38
|
-
dict_mapping_columns.each { |e| belongs_to "#{e}_dict".to_sym, class_name: "Dictionary", foreign_key: e.to_sym }
|
39
|
-
dict_mapping_columns.each { |ele| named_dict_value ele.to_sym }
|
40
|
-
dict_mapping_columns.each { |ele| dict_name_equal ele.to_sym }
|
41
|
-
end
|
42
|
-
|
43
|
-
# Generate dynamic instance method named_column to consumer model
|
44
|
-
# def named_city(locale=nil)
|
45
|
-
# locale = locale.presence || default_dict_locale.presence || :en
|
46
|
-
# locale = "name_#{locale}"
|
47
|
-
# self.send(city_dict).try(:send,locale)
|
48
|
-
# end
|
49
|
-
# alias_method :city_name, :named_city
|
50
|
-
def named_dict_value(method_name)
|
51
|
-
belongs_to_name="#{method_name}_dict".to_sym
|
52
|
-
origin_method_name = method_name
|
53
|
-
method_name="named_#{method_name}"
|
54
|
-
define_method(method_name) do | locale=nil |
|
55
|
-
locale = locale.presence || default_dict_locale.presence || :en
|
56
|
-
locale = "name_#{locale}"
|
57
|
-
self.send(belongs_to_name).try(:send,locale)
|
58
|
-
end
|
59
|
-
alias_method "#{origin_method_name}_name".to_sym, method_name.to_sym
|
60
|
-
end
|
61
|
-
|
62
|
-
# Build dynamic method column_name= to the consumer model
|
63
|
-
#
|
64
|
-
# def city_name=(value, options = {})
|
65
|
-
#
|
66
|
-
#
|
67
|
-
# end
|
68
|
-
def dict_name_equal(colname)
|
69
|
-
method_name = "#{colname}_name="
|
70
|
-
belongs_to_name="#{colname}_dict".to_sym
|
71
|
-
define_method(method_name) do |value, options={}|
|
72
|
-
options.merge!(name_en: value)
|
73
|
-
dict_type_id = DictType.revert("#{self.class.table_name.singularize}_#{colname}")
|
74
|
-
options.merge!(dict_type_id: dict_type_id)
|
75
|
-
exist_dictionary = Dictionary.where(options)
|
76
|
-
if exist_dictionary.present?
|
77
|
-
exist_id = exist_dictionary.first.id
|
78
|
-
else
|
79
|
-
exist_id = send("create_#{belongs_to_name}!", options).id
|
80
|
-
end
|
81
|
-
send "#{colname}=", exist_id
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
end # END ClassMethods
|
86
|
-
|
87
|
-
end
|
88
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
module RailsDictionary
|
2
|
-
module ActsAsDictType
|
3
|
-
def self.included(base)
|
4
|
-
base.extend(ClassMethods)
|
5
|
-
base.send :include, InstanceMethods
|
6
|
-
base.mattr_accessor :whole_types
|
7
|
-
end
|
8
|
-
|
9
|
-
module ClassMethods
|
10
|
-
|
11
|
-
def all_types
|
12
|
-
whole_types ||
|
13
|
-
self.whole_types = all.map(&:name).map(&:to_sym)
|
14
|
-
end
|
15
|
-
|
16
|
-
# short method to transfer id to name or name to id
|
17
|
-
# TODO: cache it
|
18
|
-
def revert(arg)
|
19
|
-
if arg.is_a?(String)
|
20
|
-
DictType.where(name: arg).first.try(:id)
|
21
|
-
elsif arg.is_a?(Integer)
|
22
|
-
DictType.where(id: arg).first.try(:name)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
#
|
27
|
-
# Parse the name value to get which column and model(or table) are listed in DictType
|
28
|
-
#
|
29
|
-
# Programmer DOC:
|
30
|
-
# There are two chooses to get subclass,one is subclasses the other is descendants,
|
31
|
-
# I don't know which is better,but descendants contains subclass of subclass,it contains more.
|
32
|
-
#
|
33
|
-
# Class like +Ckeditor::Asset+ transfer to "ckeditor/asset",but we can not naming method like that,
|
34
|
-
# So it still not support, the solution may be simple,just make another convention to escape "/"
|
35
|
-
#
|
36
|
-
# Seems this method did not need to be cached in production.
|
37
|
-
# Because everyclass was cached before application was run.So after application was run, it never be run again.
|
38
|
-
# TODO:
|
39
|
-
# To cache this method output need more skills on how to caculate ActiveRecord::Base.descendants
|
40
|
-
# Temply remove the cache
|
41
|
-
# And add test for this situation
|
42
|
-
def tab_and_column
|
43
|
-
all_model_class=ActiveRecord::Base.descendants.map(&:name).map(&:underscore)
|
44
|
-
all_types.map(&:to_s).extract_to_hash(all_model_class)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
module InstanceMethods
|
49
|
-
def delete_all_caches
|
50
|
-
self.whole_types = nil
|
51
|
-
return true
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
end
|
data/spec/fake_app.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
# database
|
2
|
-
ActiveRecord::Base.configurations = {'test' => {:adapter => 'sqlite3', :database => ':memory:'}}
|
3
|
-
|
4
|
-
if ActiveRecord::VERSION::MAJOR >= 5
|
5
|
-
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
|
6
|
-
else
|
7
|
-
ActiveRecord::Base.establish_connection(:test)
|
8
|
-
end
|
9
|
-
|
10
|
-
# config
|
11
|
-
app = Class.new(Rails::Application)
|
12
|
-
app.config.active_support.deprecation = :log
|
13
|
-
app.config.eager_load = false
|
14
|
-
app.initialize!
|
15
|
-
|
16
|
-
# models
|
17
|
-
class DictType < ActiveRecord::Base
|
18
|
-
acts_as_dict_type
|
19
|
-
end
|
20
|
-
|
21
|
-
class Dictionary < ActiveRecord::Base
|
22
|
-
acts_as_dictionary
|
23
|
-
end
|
24
|
-
|
25
|
-
class Student < ActiveRecord::Base
|
26
|
-
end
|
27
|
-
|
28
|
-
#migrations
|
29
|
-
class CreateAllTables < ActiveRecord::VERSION::MAJOR >= 5 ? ActiveRecord::Migration[5.0] : ActiveRecord::Migration
|
30
|
-
def self.up
|
31
|
-
create_table(:dict_types) {|t| t.string :name}
|
32
|
-
create_table(:dictionaries) {|t| t.string :name_en; t.string :name_zh ; t.string :name_fr ; t.integer :dict_type_id}
|
33
|
-
create_table(:students) {|t| t.string :email; t.integer :city; t.integer :school}
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.down
|
37
|
-
drop_table :dict_types
|
38
|
-
drop_table :dictionaries
|
39
|
-
drop_table :students
|
40
|
-
end
|
41
|
-
end
|
@@ -1,122 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
3
|
-
|
4
|
-
describe RailsDictionary::ActiveRecordExtension do
|
5
|
-
%w[acts_as_dict_type acts_as_dictionary acts_as_dict_slave].each do |method_name|
|
6
|
-
it "contains #{method_name}" do
|
7
|
-
expect(ActiveRecord::Base.methods).to include(method_name.to_sym)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
describe RailsDictionary do
|
13
|
-
let!(:dt_stu_city) { DictType.create! :name => "student_city" }
|
14
|
-
let!(:dt_stu_school) { DictType.create! :name => "student_school" }
|
15
|
-
let!(:dy_shanghai) { Dictionary.create! name_en: "shanghai",name_zh: "上海",name_fr: "shanghai",dict_type_id: dt_stu_city.id }
|
16
|
-
let!(:dy_beijing) { Dictionary.create! name_en: "beijing",name_zh: "北京",name_fr: "Pékin",dict_type_id: dt_stu_city.id }
|
17
|
-
let!(:stu_beijing) { Student.create! email: "beijing@dict.com",city: dy_beijing.id }
|
18
|
-
let!(:stu_shanghai) { Student.create! email: "shanghai@dict.com",city: dy_shanghai.id }
|
19
|
-
|
20
|
-
describe DictType do
|
21
|
-
it "parse model and method" do
|
22
|
-
expected_hash={:student => %w[city school]}
|
23
|
-
DictType.tab_and_column.should == expected_hash
|
24
|
-
end
|
25
|
-
|
26
|
-
it "all types" do
|
27
|
-
DictType.all_types.should == [:student_city, :student_school]
|
28
|
-
end
|
29
|
-
|
30
|
-
it "reverts id to name or name to id" do
|
31
|
-
DictType.revert(dt_stu_school.id).should == "student_school"
|
32
|
-
DictType.revert(100).should be_nil
|
33
|
-
end
|
34
|
-
|
35
|
-
it "after one record removed" do
|
36
|
-
DictType.all_types
|
37
|
-
DictType.whole_types.should == [:student_city, :student_school]
|
38
|
-
dt_stu_school.destroy
|
39
|
-
DictType.all_types.should == [:student_city]
|
40
|
-
DictType.tab_and_column.should == Hash[:student,["city"]]
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe Dictionary do
|
45
|
-
it "should respond to student_city" do
|
46
|
-
Dictionary.should respond_to(:student_city)
|
47
|
-
end
|
48
|
-
|
49
|
-
it "generate student_city method" do
|
50
|
-
Dictionary.student_city.should == [dy_shanghai,dy_beijing]
|
51
|
-
end
|
52
|
-
|
53
|
-
it "generate student_city method with locale" do
|
54
|
-
Dictionary.student_city(:locale => :zh).should == [["北京", 2],["上海",1]]
|
55
|
-
end
|
56
|
-
|
57
|
-
it "build scope method scoped_student_city" do
|
58
|
-
Dictionary.scoped_student_city.class.name.should == "ActiveRecord::Relation"
|
59
|
-
Dictionary.scoped_student_city.where(:id => 1).should == [dy_shanghai]
|
60
|
-
end
|
61
|
-
|
62
|
-
it "after record added or removed" do
|
63
|
-
@dy_wuhan=Dictionary.create! name_en: "wuhan",name_zh: "武汉",name_fr: "wuhan",dict_type_id: dt_stu_city.id
|
64
|
-
Dictionary.student_city(:locale => :en).should == [["beijing", 2],["shanghai",1],["wuhan", 3]]
|
65
|
-
@dy_wuhan.destroy
|
66
|
-
Dictionary.student_city(:locale => :en).should == [["beijing", 2],["shanghai",1]]
|
67
|
-
end
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
describe Student do
|
72
|
-
before :each do
|
73
|
-
Student.acts_as_dict_slave
|
74
|
-
end
|
75
|
-
it "method of columns_in_dict_type and dict_columns" do
|
76
|
-
Student.columns_in_dict_type.should == %w[city school]
|
77
|
-
Student.dict_columns == %w[city school]
|
78
|
-
end
|
79
|
-
|
80
|
-
it "named_city with different locale" do
|
81
|
-
stu_shanghai.named_city(:en).should == "shanghai"
|
82
|
-
stu_shanghai.city_name(:en).should == "shanghai"
|
83
|
-
stu_shanghai.city_name.should == "shanghai"
|
84
|
-
stu_shanghai.named_city("").should == "shanghai"
|
85
|
-
stu_beijing.named_city(:fr).should == "Pékin"
|
86
|
-
end
|
87
|
-
|
88
|
-
it "update city by set city_name to a value" do
|
89
|
-
stu_shanghai.update_attributes city_name: "wuhan"
|
90
|
-
stu_shanghai.reload.city_name.should == "wuhan"
|
91
|
-
Dictionary.student_city.map(&:name_en).include?("wuhan").should be_truthy
|
92
|
-
end
|
93
|
-
|
94
|
-
it "update city by set city_name to an exist dictionary name" do
|
95
|
-
Dictionary.where(name_en: "beijing").count.should eq(1)
|
96
|
-
stu_shanghai.update_attributes city_name: "beijing"
|
97
|
-
stu_shanghai.reload.city_name.should eq('beijing')
|
98
|
-
Dictionary.where(name_en: "beijing").count.should eq(1)
|
99
|
-
end
|
100
|
-
|
101
|
-
it "create a student with shanghai city" do
|
102
|
-
s = Student.create(city_name: "shanghai")
|
103
|
-
s.reload
|
104
|
-
s.city_name.should == "shanghai"
|
105
|
-
end
|
106
|
-
|
107
|
-
it "override default locale" do
|
108
|
-
Student.acts_as_dict_slave :locale => :fr
|
109
|
-
stu_beijing.named_city.should == "Pékin"
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
describe Array do
|
115
|
-
let(:an_array) { %w[root student_school student_city admin_role] }
|
116
|
-
let(:expected_hash) { {:student => %w[school city],:admin => %w[role]} }
|
117
|
-
let(:blank_hash) { Hash.new }
|
118
|
-
it "extract to hash" do
|
119
|
-
an_array.extract_to_hash(%w[student admin]).should == expected_hash
|
120
|
-
an_array.extract_to_hash(%w[students]).should == blank_hash
|
121
|
-
end
|
122
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
# copy and modify the test design of kaminari(a paginate gem for Rails3)
|
2
|
-
RAILS_ENV = 'test'
|
3
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
4
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
5
|
-
require 'rails'
|
6
|
-
require 'active_record'
|
7
|
-
require 'action_controller/railtie'
|
8
|
-
require 'action_view/railtie'
|
9
|
-
require 'rails_dictionary'
|
10
|
-
|
11
|
-
require File.join(File.dirname(__FILE__), 'fake_app')
|
12
|
-
|
13
|
-
require 'rspec/rails'
|
14
|
-
|
15
|
-
$stdout = StringIO.new # remove the noise output
|
16
|
-
|
17
|
-
RSpec.configure do |config|
|
18
|
-
config.use_transactional_fixtures = true
|
19
|
-
# not work, must syntax error
|
20
|
-
# config.expect_with(:rspec) { |c| c.syntax = :should }
|
21
|
-
CreateAllTables.up unless ActiveRecord::Base.connection.table_exists? 'dict_types'
|
22
|
-
end
|
23
|
-
|
24
|
-
require 'byebug'
|