rails_dictionary 0.0.1

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 ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in dictionary.gemspec
4
+ gemspec
data/README.rdoc ADDED
@@ -0,0 +1,12 @@
1
+ = Intro
2
+ Mapping web static data to Dictionary Class
3
+ = Usage
4
+
5
+ ==
6
+ Rail3
7
+ gem "dictionary",:git => 'git://github.com/raykin/dictionary'
8
+
9
+ ==
10
+
11
+ ==TODO
12
+ Add test code.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ desc "Running Test"
5
+ task :test do
6
+ system "ruby -I . test/dictionary_test.rb "
7
+ end
8
+
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "dictionary/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rails_dictionary"
7
+ s.version = Dictionary::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["raykin"]
10
+ s.email = ["raykincoldxiao@campus.com"]
11
+ s.homepage = "https://github.com/raykin/dictionary"
12
+ s.summary = %q{dictionary data for application}
13
+ s.description = %q{mapping application static data to dictionary class and slave class}
14
+
15
+ s.rubyforge_project = "rails_dictionary"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
@@ -0,0 +1,59 @@
1
+ module ActsAsDictSlave
2
+ def self.included(base)
3
+ base.extend(ClassMethods)
4
+ end
5
+
6
+ module ClassMethods
7
+ # argument except will remove dynamic column method
8
+ # argument add will add dynamic column method
9
+ def acts_as_dict_slave(ops={})
10
+ @@dict_columns = dict_columns(ops)
11
+ unless @@dict_columns.nil?
12
+ add_dynamic_column_method
13
+ end
14
+ end
15
+
16
+ # return columns that exist in DictType#tab_and_column
17
+ def columns_in_dict_type
18
+ DictType.tab_and_column[self.name.downcase.to_sym]
19
+ end
20
+
21
+ # columns which map to dictionary
22
+ def dict_columns(ops={})
23
+ conf={except: nil,add: nil}
24
+ conf.update(ops)
25
+ cidt=self.columns_in_dict_type || []
26
+ cidt.delete(conf[:except])
27
+ case conf[:add]
28
+ when String
29
+ cidt.push(conf[:add])
30
+ when Array
31
+ cidt.push(*conf[:add])
32
+ else nil
33
+ end
34
+ cidt.uniq! || cidt
35
+ end
36
+
37
+ # add a belongs_to(Dictionary) association and a named_{column} method
38
+ def add_dynamic_column_method
39
+ self.extend(DynamicInsMethods)
40
+ @@dict_columns.each { |e| belongs_to "#{e.to_s}_dict".to_sym,class_name: "Dictionary",foreign_key: e }
41
+ @@dict_columns.each { |ele| named_dict_value ele.to_sym }
42
+ end
43
+ end
44
+
45
+ module DynamicInsMethods
46
+ def named_dict_value(method_name)
47
+ belongs_to_name="#{method_name.to_s}_dict".to_sym
48
+ method_name="named_#{method_name.to_s}"
49
+ define_method(method_name) do | locale=:en |
50
+ # arg.first ? locale = "name_#{arg.first}" : locale ='name_en'
51
+ locale ="name_#{locale}"
52
+ self.send(belongs_to_name).try(:send,locale)
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ end
59
+ ActiveRecord::Base.class_eval { include ActsAsDictSlave }
@@ -0,0 +1,58 @@
1
+ require "rails"
2
+ module ActsAsDictType
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+ def acts_as_dict_type(ops={})
9
+ self.class_eval do
10
+ has_many :dictionaries
11
+ include InstanceMethods
12
+ validates_uniqueness_of :name
13
+ after_save :delete_all_caches
14
+ after_destroy :delete_all_caches
15
+
16
+ def self.all_types
17
+ Rails.cache.fetch("DictType.all_types") { all.map(&:name) }.dup
18
+ end
19
+
20
+ def self.cached_all
21
+ Rails.cache.fetch("DictType.cached_all") { all }.dup
22
+ end
23
+
24
+ def self.revert(arg)
25
+ if arg.class == String
26
+ DictType.find_by_name(arg).id
27
+ elsif arg.class == Fixnum
28
+ DictType.find_by_id(arg).name
29
+ end
30
+ end
31
+
32
+ #TODO: get a more accurate method name
33
+ def self.tab_and_column
34
+ @tab_and_column={}
35
+ @all_types=all_types
36
+ #TODO: any better way to retrive the class name in app/model ?
37
+ # Here maybe a problem when class like Ckeditor::Asset(.name.underscore => "ckeditor/asset"
38
+ all_tabs=ActiveRecord::Base.connection.tables.sort.reject! do |t|
39
+ ['schema_migrations', 'sessions'].include?(t)
40
+ end
41
+ all_class=all_tabs.map(&:singularize)
42
+ all_tabs=all_class
43
+ @tab_and_column=@all_types.extract_to_hash(all_tabs)
44
+ end
45
+ end
46
+ end
47
+
48
+ module InstanceMethods
49
+ def delete_all_caches
50
+ Rails.cache.delete("DictType.all_types")
51
+ Rails.cache.delete("DictType.cached_all")
52
+ return true
53
+ end
54
+ end
55
+
56
+ end
57
+ end
58
+ ActiveRecord::Base.class_eval { include ActsAsDictType }
@@ -0,0 +1,46 @@
1
+ module ActsAsDictionary
2
+ def self.included(base)
3
+ base.extend(ClassMethods)
4
+ end
5
+
6
+ module ClassMethods
7
+ def acts_as_dictionary
8
+ self.class_eval do
9
+ include InstanceMethods
10
+ belongs_to :dict_type
11
+ after_save :delete_dicts_cache
12
+ after_destroy :delete_dicts_cache
13
+
14
+ # TODO: need to add more function
15
+ def self.method_missing(method_id,options={},&block)
16
+ method_name=method_id.to_s.downcase
17
+ if DictType.all_types.include? method_id.to_s
18
+ Rails.cache.fetch("Dictionary.#{method_name}") { Dictionary.joins(:dict_type).where('dict_types.name'=>method_name).all }
19
+ listed_attr=Rails.cache.read("Dictionary.#{method_name}").dup
20
+ if options.keys.include? :locale
21
+ locale="name_#{options[:locale]}"
22
+ listed_attr.map! { |a| [a.send(locale),a.id] }
23
+ listed_attr.sort {|a,b| a.last <=> b.last } # maybe remove this one
24
+ else
25
+ listed_attr
26
+ end
27
+ else
28
+ super
29
+ end
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
36
+
37
+ module InstanceMethods
38
+ def delete_dicts_cache
39
+ method_name=DictType.revert(self.dict_type_id)
40
+ Rails.cache.delete("Dictionary.#{method_name}")
41
+ return true
42
+ end
43
+ end
44
+
45
+ end
46
+ ActiveRecord::Base.class_eval { include ActsAsDictionary }
@@ -0,0 +1,13 @@
1
+ class Array
2
+ # returning a hash,not array
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
@@ -0,0 +1,3 @@
1
+ module Dictionary
2
+ VERSION = "0.0.1"
3
+ end
data/lib/dictionary.rb ADDED
@@ -0,0 +1,8 @@
1
+
2
+ #require "active_record"
3
+ require "dictionary/array_core_ext"
4
+ require "dictionary/acts_as_dictionary"
5
+ require "dictionary/acts_as_dict_slave"
6
+ require "dictionary/acts_as_dict_type"
7
+
8
+
@@ -0,0 +1,129 @@
1
+ # -*- coding: utf-8 -*-
2
+ # min test
3
+ require "test/unit"
4
+ require "active_support"
5
+ require "active_record"
6
+ require "ruby-debug"
7
+ Object.const_set "RAILS_CACHE", ActiveSupport::Cache.lookup_store
8
+ require "active_support/cache"
9
+ require "rails"
10
+ # $: << "/home/raykin/studio/dictionary/lib" # tmply added for local testing
11
+ require "#{File.dirname(__FILE__)}/../lib/dictionary.rb"
12
+
13
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
14
+
15
+ $stdout = StringIO.new
16
+
17
+ def setup_db
18
+ ActiveRecord::Base.logger
19
+ ActiveRecord::Schema.define(:version => 1) do
20
+ create_table :dict_types do |t|
21
+ t.string :name
22
+ t.string :comment
23
+ t.timestamps
24
+ end
25
+ create_table :dictionaries do |t|
26
+ t.string :name_en
27
+ t.string :name_zh
28
+ t.string :name_fr
29
+ t.integer :dict_type_id
30
+ t.timestamps
31
+ end
32
+ create_table :students do |t|
33
+ t.string :email
34
+ t.integer :city
35
+ t.integer :school
36
+ t.timestamps
37
+ end
38
+ end
39
+ end
40
+
41
+ def teardown_db
42
+ ActiveRecord::Base.connection.tables.each do |table|
43
+ ActiveRecord::Base.connection.drop_table(table)
44
+ end
45
+ end
46
+
47
+ class DictType < ActiveRecord::Base
48
+ acts_as_dict_type
49
+ end
50
+
51
+ class Dictionary < ActiveRecord::Base
52
+ acts_as_dictionary
53
+ end
54
+
55
+ class Student < ActiveRecord::Base
56
+ end
57
+
58
+
59
+ class CoreExtTest < Test::Unit::TestCase
60
+ def test_array
61
+ expected_hash={:student => %w[school city],:admin => %w[role]}
62
+ assert_equal expected_hash, %w[student_school student_city admin_role].extract_to_hash(%w[student admin])
63
+ assert_equal expected_hash, %w[root student_school student_city admin_role].extract_to_hash(%w[student admin])
64
+ end
65
+ end
66
+
67
+ class DictTypeTest < Test::Unit::TestCase
68
+ def setup
69
+ setup_db
70
+ #Object.const_set('Student',Class.new(ActiveRecord::Base))
71
+ @dt_stu_city=DictType.create! :name => "student_city"
72
+ @dt_stu_school=DictType.create! :name => "student_school"
73
+ @dy_shanghai=Dictionary.create! name_en: "shanghai",name_zh: "上海",name_fr: "shanghai",dict_type_id: @dt_stu_city.id
74
+ @dy_beijing=Dictionary.create! name_en: "beijing",name_zh: "北京",name_fr: "Pékin",dict_type_id: @dt_stu_city.id
75
+ @stu_beijing=Student.create! email: "beijing@dict.com",city: @dy_beijing.id
76
+ @stu_shanghai=Student.create! email: "shanghai@dict.com",city: @dy_shanghai.id
77
+ Student.acts_as_dict_slave
78
+ # the acts_as_dict_slave need real data to generate dynamic method
79
+ end
80
+
81
+ def teardown
82
+ teardown_db
83
+ end
84
+
85
+ def test_tab_and_column
86
+ expected_hash={:student => %w[city school]}
87
+ assert_equal expected_hash,DictType.tab_and_column
88
+ end
89
+
90
+ def test_all_types
91
+ assert_equal %w[student_city student_school],DictType.all_types
92
+ end
93
+
94
+ # test revert method in acts_as_dict_type
95
+ def test_dt_revert
96
+ assert_equal "student_school",DictType.revert(@dt_stu_school.id)
97
+ end
98
+
99
+ def test_dictionary_method_missing
100
+ assert_equal [["shanghai",1],["beijing",2]],Dictionary.student_city(:locale => :en)
101
+ end
102
+
103
+ def test_dictionary_method_missing_with_locale
104
+ assert_equal [["上海", 1], ["北京", 2]],Dictionary.student_city(:locale => :zh)
105
+ end
106
+
107
+ # test dynamic instance methods in slave model
108
+ def test_named_city
109
+ assert_equal %w[city school],Student.columns_in_dict_type
110
+ assert_equal %w[city school],Student.dict_columns
111
+ assert_equal "shanghai",@stu_shanghai.named_city(:en)
112
+ assert_equal "Pékin",@stu_beijing.named_city(:fr)
113
+ end
114
+
115
+ def test_delete_dicts_cache
116
+ @dy_wuhan=Dictionary.create! name_en: "wuhan",name_zh: "武汉",name_fr: "wuhan",dict_type_id: @dt_stu_city.id
117
+ assert_equal [["shanghai", 1], ["beijing", 2], ["wuhan", 3]],Dictionary.student_city(:locale => :en)
118
+ @dy_wuhan.destroy
119
+ assert_equal [["shanghai", 1], ["beijing", 2]],Dictionary.student_city(:locale => :en)
120
+ assert_equal [@dy_shanghai,@dy_beijing],Dictionary.student_city
121
+ end
122
+
123
+ def test_delete_all_caches
124
+ assert_equal %w[student_city student_school],DictType.all_types
125
+ @dt_stu_school.destroy
126
+ assert_equal %w[student_city],DictType.all_types
127
+ end
128
+
129
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_dictionary
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - raykin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-02-26 00:00:00 +08:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: mapping application static data to dictionary class and slave class
18
+ email:
19
+ - raykincoldxiao@campus.com
20
+ executables: []
21
+
22
+ extensions: []
23
+
24
+ extra_rdoc_files: []
25
+
26
+ files:
27
+ - .gitignore
28
+ - Gemfile
29
+ - README.rdoc
30
+ - Rakefile
31
+ - dictionary.gemspec
32
+ - lib/dictionary.rb
33
+ - lib/dictionary/acts_as_dict_slave.rb
34
+ - lib/dictionary/acts_as_dict_type.rb
35
+ - lib/dictionary/acts_as_dictionary.rb
36
+ - lib/dictionary/array_core_ext.rb
37
+ - lib/dictionary/version.rb
38
+ - test/dictionary_test.rb
39
+ has_rdoc: true
40
+ homepage: https://github.com/raykin/dictionary
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options: []
45
+
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ requirements: []
61
+
62
+ rubyforge_project: rails_dictionary
63
+ rubygems_version: 1.5.2
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: dictionary data for application
67
+ test_files:
68
+ - test/dictionary_test.rb