rails_dictionary 0.2.3 → 0.3.pre.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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'
|