rails_dictionary 0.0.8 → 0.0.9

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.
data/.gitignore CHANGED
@@ -1 +1,3 @@
1
- pkg/
1
+ pkg/
2
+ .git/
3
+ .gitignore
data/CHANGELOG ADDED
@@ -0,0 +1,6 @@
1
+ 0.0.9
2
+ add Rails Engine to redesign the gem
3
+ use Rspec instead of Test::Unit to write test code
4
+ remove many nonsence code
5
+ 0.0.1-0.0.8
6
+ old mixin coding style
data/Gemfile CHANGED
@@ -1,4 +1,10 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- # Specify your gem's dependencies in dictionary.gemspec
3
+ # Specify your gem's dependencies in rails_dictionary.gemspec
4
4
  gemspec
5
+
6
+ group :development,:test do
7
+ gem 'rspec', '>= 2.5.0'
8
+ gem 'rails', '>= 3.0.0'
9
+ gem 'sqlite3'
10
+ end
data/README.rdoc CHANGED
@@ -1,6 +1,7 @@
1
1
  = Intro
2
- There are many static data in application.
3
- For example in a student application,there may be some static data like diploma kind,school and city of school.This gem can map these static data to a Dictionary#method like Dictionary#student_diploma_kind which return data list of diploma kind and generate a list of instance method on Student like @student.named_city which return city name of @student city
2
+ There are always some static data(not static page) in application.For example product type or diploma kind of student.
3
+
4
+ This gem can map these static data to a Dictionary#method like Dictionary#student_diploma_kind and generate a list of instance method on Student like @student.named_city which return city name (with locale if you need).
4
5
 
5
6
  = Usage
6
7
  == Installation
@@ -43,10 +44,11 @@ These task are just generate table dictionaries,dict_types,students and some sam
43
44
  | 2 | shanghai@dict.com | 3 | |
44
45
  +----+-------------------+------+--------+
45
46
  2 rows in set
46
- There is one conventions of DictType.name value.All value of DictType.name is "model_method" : student is model and city is method of student model.
47
+ There is one convention of DictType.name value.All value of DictType.name is "model_method" : student is model and city is method of student model.
47
48
 
48
49
  === Table Definition
49
50
  Make sure you have two tables which named as dict_types and dictionaries.
51
+
50
52
  Table dictionaries has one convention of naming column : name_locale.So the name_fr means this column have a french value,you can see more usage later.
51
53
  The students table is not required and variable by your application.
52
54
 
@@ -65,13 +67,15 @@ Here is what should be like.Student model can be other models.
65
67
  acts_as_dict_slave
66
68
  end
67
69
 
68
- == Features : Methods and results (relies on the above data)
70
+ == Features (relies on the above data) :
69
71
  DictType.all_cached #=> return cache of DictType.all
70
72
  DictType.all_types = %w[student_city student_school] # also cached
71
73
  Dictionary.student_city #=> [Dictionary.find(5),Dictionary.find(6)]
72
- student_city is a dynamic method which returns a list of dictionary object which dict_type is "student_city".Actually Dictionary will have as many dynamic methods as DictType.count and each dynamic method name is DictType.name(This methods returning an array,not ActiveRelation).
74
+ student_city is a dynamic method which returns a list of dictionary object which dict_type is "student_city".
75
+ Actually Dictionary will have as many dynamic methods as DictType.count and each dynamic method name is DictType.name.
76
+ Before version 0.1.0 or 0.2.0 ,all dynamic methods return an array,not ActiveRelation.So
73
77
  Dictionary.student_school = []
74
- Dictionary.student_city :locale => :en = [["shanghai",1],["beijing",2]]
78
+ Dictionary.student_city :locale => :en #=> [["shanghai",1],["beijing",2]]
75
79
  You can use it in form select method like
76
80
  collection_select :student,:city,Dictionary.student_city,:id,:name_en
77
81
  select :student,:city,Dictionary.student_city(params)
@@ -80,6 +84,9 @@ If params contains :locale => :fr,it returns a list of french name of student ci
80
84
  Here is an other solution for international translation.
81
85
  Student.find(1).named_city(:zh) = "北京"
82
86
  Student.find(1).named_city(:fr) = "Pékin"
87
+ Student.find(1).named_city(:en) = "beijing"
88
+ Make sure your locale is en,not en-US.
89
+
83
90
  Student has two belongs_to assocition which named as city_dict and school_dict,the naming convention is method_dict.
84
91
  Student.find(1).city_dict #=> Dictionary.find(6)
85
92
 
@@ -97,5 +104,10 @@ The rails cache would not refresh.
97
104
  In short,when you confused with the debug data,try running "rails tmp:clear" first.
98
105
 
99
106
  = TODO & Problems
100
- There are no convention and implemention to map Class like Ckeditor::Asset to a method.
107
+ There are no convention and implemention to map Class like Ckeditor::Asset to a legal method name.
108
+
109
+ Rebuild core code.Using Rails engine.
110
+
111
+ Make cached type of DictType to an array of symbols
112
+
101
113
  Rewrite Testing,make it more maintainable.
data/Rakefile CHANGED
@@ -3,6 +3,7 @@ Bundler::GemHelper.install_tasks
3
3
 
4
4
  desc "Running Test"
5
5
  task :test do
6
- system "ruby -I . test/rails_dictionary_test.rb "
6
+ # system "ruby -I . test/rails_dictionary_test.rb " # used with version 0.0.8 or before it
7
+ system "rspec spec/rails_dictionary_spec.rb"
7
8
  end
8
9
 
@@ -0,0 +1,4 @@
1
+ module RailsDictionary
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,45 @@
1
+ module RailsDictionary
2
+ module ActiveRecordExtension
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
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
+ self.class_eval do
12
+ has_many :dictionaries
13
+ validates_uniqueness_of :name
14
+ after_save :delete_all_caches
15
+ after_destroy :delete_all_caches
16
+ end
17
+ include RailsDictionary::ActsAsDictType
18
+ end
19
+
20
+ def acts_as_dictionary
21
+ self.class_eval do
22
+ belongs_to :dict_type
23
+ after_save :delete_dicts_cache
24
+ after_destroy :delete_dicts_cache
25
+ end
26
+ include RailsDictionary::ActsAsDictionary
27
+ end
28
+
29
+ # :except - remove dict mapping column
30
+ # :add - add dict mapping column
31
+ # :locale - add and initialize class attribute default_dict_locale
32
+ def acts_as_dict_slave(ops={})
33
+ include RailsDictionary::ActsAsDictSlave
34
+ class_attribute :default_dict_locale,:instance_writer => false
35
+ cattr_accessor :dict_mapping_columns,:instance_writes => false
36
+ self.default_dict_locale = ops[:locale] if ops[:locale]
37
+ self.dict_mapping_columns = dict_columns(ops)
38
+ unless dict_mapping_columns.nil?
39
+ add_dynamic_column_method
40
+ end
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,55 @@
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
+ DictType.tab_and_column[self.name.underscore.to_sym]
12
+ end
13
+
14
+ # columns which map to dictionary
15
+ def dict_columns(ops={})
16
+ conf={except: nil,add: nil}
17
+ conf.update(ops)
18
+ cidt=self.columns_in_dict_type || []
19
+ cidt.delete(conf[:except])
20
+ case conf[:add]
21
+ when String
22
+ cidt.push(conf[:add])
23
+ when Array
24
+ cidt.push(*conf[:add])
25
+ else nil
26
+ end
27
+ cidt.uniq! || cidt
28
+ end
29
+
30
+ # add a belongs_to(Dictionary) association and a named_{column} method
31
+ def add_dynamic_column_method
32
+ dict_mapping_columns.each { |e| belongs_to "#{e.to_s}_dict".to_sym,class_name: "Dictionary",foreign_key: e }
33
+ dict_mapping_columns.each { |ele| named_dict_value ele.to_sym }
34
+ end
35
+
36
+ # Generate dynamic instance method named_column to slave model
37
+ # def named_city(locale=nil)
38
+ # locale = locale.presence || default_dict_locale.presence || :en
39
+ # locale = "name_#{locale}"
40
+ # self.send(city_dict).try(:send,locale)
41
+ # end
42
+ def named_dict_value(method_name)
43
+ belongs_to_name="#{method_name.to_s}_dict".to_sym
44
+ method_name="named_#{method_name.to_s}"
45
+ define_method(method_name) do | locale=nil |
46
+ locale = locale.presence || default_dict_locale.presence || :en
47
+ locale = "name_#{locale}"
48
+ self.send(belongs_to_name).try(:send,locale)
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,54 @@
1
+ module RailsDictionary
2
+ module ActsAsDictType
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ base.send :include,InstanceMethods
6
+ end
7
+
8
+ module ClassMethods
9
+
10
+ def all_types
11
+ Rails.cache.fetch("DictType.all_types") { all.map(&:name).map(&:to_sym) }.dup
12
+ end
13
+
14
+ def cached_all
15
+ Rails.cache.fetch("DictType.cached_all") { all }.dup
16
+ end
17
+
18
+ # short method to transfer id to name or name to id
19
+ def revert(arg)
20
+ if arg.is_a?(String)
21
+ DictType.where(name: arg).first.try(:id)
22
+ elsif arg.is_a?(Fixnum)
23
+ DictType.where(id: arg).first.try(:name)
24
+ end
25
+ end
26
+
27
+ # TODO: get a more accurate method name
28
+ #
29
+ # Parse the name value to get which column and model are listed in DictType
30
+ #
31
+ # Programmer DOC:
32
+ # There are two chooses to get subclass,one is subclasses the other is descendants,
33
+ # I don't know which is better,but descendants contains subclass of subclass,it contains more.
34
+ # Class like +Ckeditor::Asset+ transfer to "ckeditor/asset",but we can not naming method like that,
35
+ # So it still not support, the solution may be simple,just make another convention to escape "/"
36
+ def tab_and_column
37
+ Rails.cache.fetch("DictType.tab_and_column") do
38
+ all_model_class=ActiveRecord::Base.descendants.map(&:name).map(&:underscore)
39
+ all_types.map(&:to_s).extract_to_hash(all_model_class)
40
+ end
41
+ end
42
+ end
43
+
44
+ module InstanceMethods
45
+ def delete_all_caches
46
+ Rails.cache.delete("DictType.all_types")
47
+ Rails.cache.delete("DictType.cached_all")
48
+ Rails.cache.delete("DictType.tab_and_column")
49
+ return true
50
+ end
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,56 @@
1
+ module RailsDictionary
2
+ module ActsAsDictionary
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ base.send :include,InstanceMethods
6
+ end
7
+
8
+ module ClassMethods
9
+
10
+ # Return an instance of array
11
+ # Programmer DOC:
12
+ # Following design is failed with sqlite3 in test
13
+ # scope :dict_type_name_eq,lambda {|method_name| joins(:dict_type).where("dict_types.name" => method_name)}
14
+ # remove the all seems not pass test,return following errors
15
+ # TypeError: no marshal_dump is defined for class SQLite3::Database
16
+ def dict_type_name_eq(method_name)
17
+ joins(:dict_type).where("dict_types.name" => method_name).all
18
+ end
19
+
20
+ # Generate methods like Dictionary.student_city
21
+ # Dictionary.student_city - a list of dictionary object which dict type is student_city
22
+ # Dictionary.student_city(:locale => :zh) - a select format array which can be used
23
+ # in view method select as choice params
24
+ # Programmer DOC && TODO:
25
+ # rethink about the cache.
26
+ # cache methods like Dictionary.student_city(:locale => :zh,:sort => :name_fr)
27
+ # but not cache Dictionary.student_city,return it as relation
28
+ def method_missing(method_id,options={},&block)
29
+ method_name=method_id.to_s.downcase
30
+ if DictType.all_types.include? method_id
31
+ Rails.cache.fetch("Dictionary.#{method_name}") { dict_type_name_eq(method_name) }
32
+ listed_attr=Rails.cache.read("Dictionary.#{method_name}").dup
33
+ # Instance of activerelation can not be dup?
34
+ if options.keys.include? :locale or options.keys.include? "locale"
35
+ locale="name_#{ options[:locale] }"
36
+ listed_attr.map! { |a| [a.send(locale),a.id] }
37
+ listed_attr.sort { |a,b| a.first <=> b.first }
38
+ # maybe remove the above line,or change some sorting and caching design
39
+ else
40
+ listed_attr
41
+ end
42
+ else
43
+ super
44
+ end
45
+ end
46
+ end
47
+
48
+ module InstanceMethods
49
+ def delete_dicts_cache
50
+ method_name=DictType.revert(self.dict_type_id)
51
+ Rails.cache.delete("Dictionary.#{method_name}")
52
+ return true
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,17 @@
1
+ require 'rails'
2
+
3
+ require File.join(File.dirname(__FILE__),"array_core_ext")
4
+ require File.join(File.dirname(__FILE__),"models/acts_as_dict_type")
5
+ require File.join(File.dirname(__FILE__),"models/acts_as_dictionary")
6
+ require File.join(File.dirname(__FILE__),"models/acts_as_dict_slave")
7
+
8
+ module RailsDictionary
9
+ class Railtie < ::Rails::Railtie
10
+ initializer 'rails_dictionary' do |app|
11
+ ActiveSupport.on_load(:active_record) do
12
+ require File.join(File.dirname(__FILE__), 'models/active_record_extension')
13
+ ::ActiveRecord::Base.send :include, RailsDictionary::ActiveRecordExtension
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,3 +1,3 @@
1
1
  module RailsDictionary
2
- VERSION = "0.0.8"
2
+ VERSION = "0.0.9"
3
3
  end
@@ -1,4 +1,2 @@
1
- require "rails_dictionary/acts_as_dictionary"
2
- require "rails_dictionary/acts_as_dict_slave"
3
- require "rails_dictionary/acts_as_dict_type"
4
- require "rails_dictionary/array_core_ext"
1
+ require File.join(File.dirname(__FILE__), 'rails_dictionary/railtie')
2
+ require File.join(File.dirname(__FILE__), 'rails_dictionary/engine')
@@ -0,0 +1,2 @@
1
+
2
+ ***** Debugger requested, but was not available (ensure ruby-debug is listed in Gemfile/installed as gem): Start server with --debugger to enable *****
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
6
6
  s.name = "rails_dictionary"
7
7
  s.version = RailsDictionary::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
- s.authors = ["raykin"]
9
+ s.authors = ["Raykin Lee"]
10
10
  s.email = ["raykincoldxiao@campus.com"]
11
11
  s.homepage = "https://github.com/raykin/rails_dictionary"
12
12
  s.summary = %q{dictionary data for web application}
data/spec/fake_app.rb ADDED
@@ -0,0 +1,36 @@
1
+
2
+ # database
3
+ ActiveRecord::Base.configurations = {'test' => {:adapter => 'sqlite3', :database => ':memory:'}}
4
+ ActiveRecord::Base.establish_connection('test')
5
+
6
+ # config
7
+ app = Class.new(Rails::Application)
8
+ app.config.active_support.deprecation = :log
9
+ app.initialize!
10
+
11
+ # models
12
+ class DictType < ActiveRecord::Base
13
+ acts_as_dict_type
14
+ end
15
+
16
+ class Dictionary < ActiveRecord::Base
17
+ acts_as_dictionary
18
+ end
19
+
20
+ class Student < ActiveRecord::Base
21
+ end
22
+
23
+ #migrations
24
+ class CreateAllTables < ActiveRecord::Migration
25
+ def self.up
26
+ create_table(:dict_types) {|t| t.string :name}
27
+ create_table(:dictionaries) {|t| t.string :name_en; t.string :name_zh ; t.string :name_fr ; t.integer :dict_type_id}
28
+ create_table(:students) {|t| t.string :email; t.integer :city; t.integer :school}
29
+ end
30
+
31
+ def self.down
32
+ drop_table :dict_types
33
+ drop_table :dictionaries
34
+ drop_table :students
35
+ end
36
+ end
@@ -0,0 +1,90 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
3
+
4
+
5
+ describe RailsDictionary::ActiveRecordExtension do
6
+ %w[acts_as_dict_type acts_as_dictionary acts_as_dict_slave].each do |method_name|
7
+ it "contains #{method_name}" do
8
+ ActiveRecord::Base.methods.include?(method_name.to_sym).should be_true
9
+ end
10
+ end
11
+ end
12
+
13
+ describe RailsDictionary do
14
+ let!(:dt_stu_city) { DictType.create! :name => "student_city" }
15
+ let!(:dt_stu_school) { DictType.create! :name => "student_school" }
16
+ let!(:dy_shanghai) { Dictionary.create! name_en: "shanghai",name_zh: "上海",name_fr: "shanghai",dict_type_id: dt_stu_city.id }
17
+ let!(:dy_beijing) { Dictionary.create! name_en: "beijing",name_zh: "北京",name_fr: "Pékin",dict_type_id: dt_stu_city.id }
18
+ let!(:stu_beijing) { Student.create! email: "beijing@dict.com",city: dy_beijing.id }
19
+ let!(:stu_shanghai) { Student.create! email: "shanghai@dict.com",city: dy_shanghai.id }
20
+
21
+ describe DictType do
22
+ it "parse model and method" do
23
+ expected_hash={:student => %w[city school]}
24
+ DictType.tab_and_column.should == expected_hash
25
+ end
26
+
27
+ it "all types" do
28
+ DictType.all_types.should == [:student_city, :student_school]
29
+ end
30
+
31
+ it "reverts id to name or name to id" do
32
+ DictType.revert(dt_stu_school.id).should == "student_school"
33
+ DictType.revert(100).should be_nil
34
+ end
35
+
36
+ it "after one record removed" do
37
+ dt_stu_school.destroy
38
+ DictType.all_types.should == [:student_city]
39
+ DictType.tab_and_column.should == Hash[:student,["city"]]
40
+ end
41
+ end
42
+
43
+ describe Dictionary do
44
+ it "generate student_city method" do
45
+ Dictionary.student_city.should == [dy_shanghai,dy_beijing]
46
+ end
47
+
48
+ it "generate student_city method with locale" do
49
+ Dictionary.student_city(:locale => :zh).should == [["上海", 1],["北京", 2]]
50
+ end
51
+
52
+ it "after record added or removed" do
53
+ @dy_wuhan=Dictionary.create! name_en: "wuhan",name_zh: "武汉",name_fr: "wuhan",dict_type_id: dt_stu_city.id
54
+ Dictionary.student_city(:locale => :en).should == [["beijing", 2],["shanghai",1],["wuhan", 3]]
55
+ @dy_wuhan.destroy
56
+ Dictionary.student_city(:locale => :en).should == [["beijing", 2],["shanghai",1]]
57
+ end
58
+ end
59
+
60
+ describe Student do
61
+ before :each do
62
+ Student.acts_as_dict_slave
63
+ end
64
+ it "method of columns_in_dict_type and dict_columns" do
65
+ Student.columns_in_dict_type.should == %w[city school]
66
+ Student.dict_columns == %w[city school]
67
+ end
68
+
69
+ it "named_city with different locale" do
70
+ stu_shanghai.named_city(:en).should == "shanghai"
71
+ stu_shanghai.named_city("").should == "shanghai"
72
+ stu_beijing.named_city(:fr).should == "Pékin"
73
+ end
74
+
75
+ it "override default locale" do
76
+ Student.acts_as_dict_slave :locale => :fr
77
+ stu_beijing.named_city.should == "Pékin"
78
+ end
79
+ end
80
+ end
81
+
82
+ describe Array do
83
+ let(:an_array) { %w[root student_school student_city admin_role] }
84
+ let(:expected_hash) { {:student => %w[school city],:admin => %w[role]} }
85
+ let(:blank_hash) { Hash.new }
86
+ it "extract to hash" do
87
+ an_array.extract_to_hash(%w[student admin]).should == expected_hash
88
+ an_array.extract_to_hash(%w[students]).should == blank_hash
89
+ end
90
+ end
@@ -0,0 +1,19 @@
1
+ # copy and modify the test design of kaminari(a paginate gem for Rails3)
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
4
+ require 'rails'
5
+ require 'active_record'
6
+ require 'action_controller/railtie'
7
+ require 'action_view/railtie'
8
+ require 'rails_dictionary'
9
+
10
+ require File.join(File.dirname(__FILE__), 'fake_app')
11
+
12
+ require 'rspec/rails'
13
+
14
+ $stdout = StringIO.new # remove the noise output
15
+
16
+ RSpec.configure do |config|
17
+ config.use_transactional_fixtures = true
18
+ CreateAllTables.up unless ActiveRecord::Base.connection.table_exists? 'dict_types'
19
+ end
@@ -1,4 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
+ # Testing for version 0.0.8 or lower.Copy the test design from acts_as_tree
3
+ # Usage: run "ruby -I . test/rails_dictionary_test.rb " in root dir
4
+ #
2
5
  require "test/unit"
3
6
  require "active_support"
4
7
  require "active_record"
@@ -6,7 +9,6 @@ require "ruby-debug" # coupled with debugger to debug code
6
9
  Object.const_set "RAILS_CACHE", ActiveSupport::Cache.lookup_store
7
10
  require "active_support/cache"
8
11
  require "rails"
9
- # $: << "/home/raykin/studio/rails_dictionary/lib" # tmply added for local testing
10
12
  require "#{File.dirname(__FILE__)}/../lib/rails_dictionary.rb"
11
13
 
12
14
  ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
@@ -53,7 +55,6 @@ end
53
55
  class Student < ActiveRecord::Base
54
56
  end
55
57
 
56
-
57
58
  class CoreExtTest < Test::Unit::TestCase
58
59
  def test_array
59
60
  expected_hash={:student => %w[school city],:admin => %w[role]}
@@ -92,6 +93,7 @@ class DictTypeTest < Test::Unit::TestCase
92
93
  # test revert method in acts_as_dict_type
93
94
  def test_dt_revert
94
95
  assert_equal "student_school",DictType.revert(@dt_stu_school.id)
96
+ assert_equal nil,DictType.revert(100)
95
97
  end
96
98
 
97
99
  # test dynamic instance methods in slave model
@@ -111,18 +113,18 @@ class DictTypeTest < Test::Unit::TestCase
111
113
  end
112
114
 
113
115
  def test_dictionary_method_missing
114
- assert_equal [["shanghai",1],["beijing",2]],Dictionary.student_city(:locale => :en)
116
+ assert_equal [["beijing",2],["shanghai",1]],Dictionary.student_city(:locale => :en)
115
117
  end
116
118
 
117
119
  def test_dictionary_method_missing_with_locale
118
- assert_equal [["上海", 1], ["北京", 2]],Dictionary.student_city(:locale => :zh)
120
+ assert_equal [["上海", 1],["北京", 2]],Dictionary.student_city(:locale => :zh)
119
121
  end
120
122
 
121
123
  def test_delete_dicts_cache
122
124
  @dy_wuhan=Dictionary.create! name_en: "wuhan",name_zh: "武汉",name_fr: "wuhan",dict_type_id: @dt_stu_city.id
123
- assert_equal [["shanghai", 1], ["beijing", 2], ["wuhan", 3]],Dictionary.student_city(:locale => :en)
125
+ assert_equal [["beijing", 2],["shanghai",1],["wuhan", 3]],Dictionary.student_city(:locale => :en)
124
126
  @dy_wuhan.destroy
125
- assert_equal [["shanghai", 1], ["beijing", 2]],Dictionary.student_city(:locale => :en)
127
+ assert_equal [["beijing", 2],["shanghai",1]],Dictionary.student_city(:locale => :en)
126
128
  assert_equal [@dy_shanghai,@dy_beijing],Dictionary.student_city
127
129
  end
128
130
 
metadata CHANGED
@@ -2,16 +2,15 @@
2
2
  name: rails_dictionary
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.8
5
+ version: 0.0.9
6
6
  platform: ruby
7
7
  authors:
8
- - raykin
8
+ - Raykin Lee
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-03-21 00:00:00 +08:00
14
- default_executable:
13
+ date: 2011-04-14 00:00:00 Z
15
14
  dependencies: []
16
15
 
17
16
  description: Rails plugin for mapping static data of web application to Dictionary class
@@ -25,19 +24,26 @@ extra_rdoc_files: []
25
24
 
26
25
  files:
27
26
  - .gitignore
27
+ - CHANGELOG
28
28
  - Gemfile
29
29
  - README.rdoc
30
30
  - Rakefile
31
31
  - lib/rails_dictionary.rb
32
- - lib/rails_dictionary/acts_as_dict_slave.rb
33
- - lib/rails_dictionary/acts_as_dict_type.rb
34
- - lib/rails_dictionary/acts_as_dictionary.rb
35
32
  - lib/rails_dictionary/array_core_ext.rb
33
+ - lib/rails_dictionary/engine.rb
34
+ - lib/rails_dictionary/models/active_record_extension.rb
35
+ - lib/rails_dictionary/models/acts_as_dict_slave.rb
36
+ - lib/rails_dictionary/models/acts_as_dict_type.rb
37
+ - lib/rails_dictionary/models/acts_as_dictionary.rb
38
+ - lib/rails_dictionary/railtie.rb
36
39
  - lib/rails_dictionary/version.rb
37
40
  - lib/tasks/dicts.rake
41
+ - log/development.log
38
42
  - rails_dictionary.gemspec
43
+ - spec/fake_app.rb
44
+ - spec/rails_dictionary_spec.rb
45
+ - spec/spec_helper.rb
39
46
  - test/rails_dictionary_test.rb
40
- has_rdoc: true
41
47
  homepage: https://github.com/raykin/rails_dictionary
42
48
  licenses: []
43
49
 
@@ -61,9 +67,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
61
67
  requirements: []
62
68
 
63
69
  rubyforge_project: rails_dictionary
64
- rubygems_version: 1.6.2
70
+ rubygems_version: 1.7.2
65
71
  signing_key:
66
72
  specification_version: 3
67
73
  summary: dictionary data for web application
68
74
  test_files:
75
+ - spec/fake_app.rb
76
+ - spec/rails_dictionary_spec.rb
77
+ - spec/spec_helper.rb
69
78
  - test/rails_dictionary_test.rb
79
+ has_rdoc:
@@ -1,69 +0,0 @@
1
- module ActsAsDictSlave
2
- def self.included(base)
3
- base.extend(ClassMethods)
4
- end
5
-
6
- module ClassMethods
7
- # :except - remove dict mapping column
8
- # :add - add dict mapping column
9
- # :locale - add and initialize class attribute default_dict_locale
10
- def acts_as_dict_slave(ops={})
11
- class_attribute :default_dict_locale,:instance_writer => false
12
- cattr_accessor :dict_mapping_columns,:instance_writes => false
13
- self.default_dict_locale = ops[:locale] if ops[:locale]
14
- self.dict_mapping_columns = dict_columns(ops)
15
- unless dict_mapping_columns.nil?
16
- add_dynamic_column_method
17
- end
18
- end
19
-
20
- # return columns that exist in DictType#tab_and_column
21
- def columns_in_dict_type
22
- DictType.tab_and_column[self.name.underscore.to_sym]
23
- end
24
-
25
- # columns which map to dictionary
26
- def dict_columns(ops={})
27
- conf={except: nil,add: nil}
28
- conf.update(ops)
29
- cidt=self.columns_in_dict_type || []
30
- cidt.delete(conf[:except])
31
- case conf[:add]
32
- when String
33
- cidt.push(conf[:add])
34
- when Array
35
- cidt.push(*conf[:add])
36
- else nil
37
- end
38
- cidt.uniq! || cidt
39
- end
40
-
41
- # add a belongs_to(Dictionary) association and a named_{column} method
42
- def add_dynamic_column_method
43
- self.extend(DynamicInsMethods)
44
- dict_mapping_columns.each { |e| belongs_to "#{e.to_s}_dict".to_sym,class_name: "Dictionary",foreign_key: e }
45
- dict_mapping_columns.each { |ele| named_dict_value ele.to_sym }
46
- end
47
- end
48
-
49
- module DynamicInsMethods
50
- # generate dynamic instance method named_column to slave model
51
- # def named_city(locale=nil)
52
- # locale = locale.presence || default_dict_locale.presence || :en
53
- # locale = "name_#{locale}"
54
- # self.send(city_dict).try(:send,locale)
55
- # end
56
- def named_dict_value(method_name)
57
- belongs_to_name="#{method_name.to_s}_dict".to_sym
58
- method_name="named_#{method_name.to_s}"
59
- define_method(method_name) do | locale=nil |
60
- locale = locale.presence || default_dict_locale.presence || :en
61
- locale = "name_#{locale}"
62
- self.send(belongs_to_name).try(:send,locale)
63
- end
64
- end
65
-
66
- end
67
-
68
- end
69
- ActiveRecord::Base.class_eval { include ActsAsDictSlave }
@@ -1,56 +0,0 @@
1
- module ActsAsDictType
2
- def self.included(base)
3
- base.extend(ClassMethods)
4
- end
5
-
6
- module ClassMethods
7
- def acts_as_dict_type(ops={})
8
- self.class_eval do
9
- has_many :dictionaries
10
- include InstanceMethods
11
- validates_uniqueness_of :name
12
- after_save :delete_all_caches
13
- after_destroy :delete_all_caches
14
-
15
- def self.all_types
16
- Rails.cache.fetch("DictType.all_types") { all.map(&:name) }.dup
17
- end
18
-
19
- def self.cached_all
20
- Rails.cache.fetch("DictType.cached_all") { all }.dup
21
- end
22
-
23
- # short method to transfer id to name or name to id
24
- def self.revert(arg)
25
- if arg.is_a?(String)
26
- DictType.where(name: arg).try(:first).id
27
- elsif arg.is_a?(Fixnum)
28
- DictType.where(id: arg).try(:first).name
29
- end
30
- end
31
-
32
- # TODO: get a more accurate method name
33
- # Parse the name value to get which column and model are listed in DictType
34
- def self.tab_and_column
35
- tab_and_column={}
36
- # There are two chooses,one is subclasses the other is descendants,
37
- # I don't know which is better,but descendants contains subclass of subclass,it contains more.
38
- # Class like +Ckeditor::Asset+ transfer to "ckeditor/asset",but we can not naming method like that,
39
- # So it still not support, the solution may be simple,just make another convention to escape "/"
40
- all_model_class=ActiveRecord::Base.descendants.map(&:name).map(&:underscore)
41
- tab_and_column=all_types.extract_to_hash(all_model_class)
42
- end
43
- end
44
- end
45
-
46
- module InstanceMethods
47
- def delete_all_caches
48
- Rails.cache.delete("DictType.all_types")
49
- Rails.cache.delete("DictType.cached_all")
50
- return true
51
- end
52
- end
53
-
54
- end
55
- end
56
- ActiveRecord::Base.class_eval { include ActsAsDictType }
@@ -1,57 +0,0 @@
1
- module ActsAsDictionary
2
- def self.included(base)
3
- base.extend(ClassMethods)
4
- end
5
-
6
- module ClassMethods
7
-
8
- def acts_as_dictionary
9
- belongs_to :dict_type
10
- after_save :delete_dicts_cache
11
- after_destroy :delete_dicts_cache
12
-
13
- # Return an instance of array
14
- def dict_type_name_eq(method_name)
15
- joins(:dict_type).where("dict_types.name" => method_name).all
16
- end
17
- #Following design is not successed with sqlite3 in test
18
- # scope :dict_type_name_eq,lambda {|method_name| joins(:dict_type).where("dict_types.name" => method_name)}
19
- # remove the all seems not pass test,return following errors
20
- # TypeError: no marshal_dump is defined for class SQLite3::Database
21
- include InstanceMethods
22
- # Generate methods like Dictionary.student_city
23
- # Dictionary.student_city - a list of dictionary object which dict type is student_city
24
- # Dictionary.student_city(:locale => :zh) - a select format array which can be used
25
- # in view method select as choice params
26
- # Is this design good?
27
- def self.method_missing(method_id,options={},&block)
28
- method_name=method_id.to_s.downcase
29
- if DictType.all_types.include? method_id.to_s
30
- Rails.cache.fetch("Dictionary.#{method_name}") { dict_type_name_eq(method_name) }
31
- listed_attr=Rails.cache.read("Dictionary.#{method_name}").dup
32
- # Instance of activerelation can not be dup?
33
- if options.keys.include? :locale or options.keys.include? "locale"
34
- locale="name_#{ options[:locale] }"
35
- listed_attr.map! { |a| [a.send(locale),a.id] }
36
- listed_attr.sort {|a,b| a.last <=> b.last } # maybe remove this line
37
- else
38
- listed_attr
39
- end
40
- else
41
- super
42
- end
43
- end
44
-
45
- end
46
- end
47
-
48
- module InstanceMethods
49
- def delete_dicts_cache
50
- method_name=DictType.revert(self.dict_type_id)
51
- Rails.cache.delete("Dictionary.#{method_name}")
52
- return true
53
- end
54
- end
55
-
56
- end
57
- ActiveRecord::Base.class_eval { include ActsAsDictionary }