extend_at 0.2.2 → 0.2.3

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/README.markdown CHANGED
@@ -249,6 +249,41 @@ Comparations:
249
249
  * gt
250
250
  * match
251
251
 
252
+ ### Belongs to
253
+
254
+ If you like to add a belongs_to relationship, you can do it in this way:
255
+ # app/models/toolbox.rb
256
+ class Toolbox
257
+ end
258
+
259
+ # app/model/tool.rb
260
+ class Tool
261
+ extend_at extra, columns => {}, :belongs_to => :toolbox
262
+ end
263
+
264
+ <code>:belongs_to</code> parametter accept
265
+
266
+ * One name
267
+
268
+ :belongs_to => :toolbox
269
+
270
+ * Array of names
271
+
272
+ :belongs_to => [:toolbox, :owner]
273
+
274
+ * Hash
275
+
276
+ :belongs_to => :onwer => {:class_name => "User"}
277
+
278
+ For now, hash only accept
279
+
280
+ * class_name
281
+ * polymorphic
282
+ * foreign_key
283
+
284
+ _Note_, this new feature is under heavy development, use it under your own risk.
285
+
286
+
252
287
  ### Integration in the views
253
288
 
254
289
  If you like to use some configuration variable in your views you only need put the name of the input like <code>:extra_name</code>, for example:
data/extend_at.gemspec CHANGED
@@ -19,8 +19,11 @@ Gem::Specification.new do |s|
19
19
  s.require_paths = ["lib"]
20
20
 
21
21
  s.add_runtime_dependency 'rails', '~> 3.1'
22
- s.add_development_dependency "rspec", '~> 2.5'
23
- s.add_development_dependency "rspec-core"
24
- s.add_development_dependency "database_cleaner", "~> 0.7"
22
+ s.add_development_dependency "rspec", '~> 2.8'
23
+ s.add_development_dependency "rspec-core", '~> 2.8'
24
+ s.add_development_dependency "rspec-expectations", '~> 2.8'
25
+ s.add_development_dependency "activesupport", '~> 3.1'
26
+ # s.add_development_dependency "rspec-mocks", '~> 2.8.0'
27
+ s.add_development_dependency "database_cleaner", "~> 0.8"
25
28
 
26
29
  end
@@ -1,12 +1,17 @@
1
1
  require File.expand_path('../environment', __FILE__)
2
2
 
3
3
  module ExtendModelAt
4
+ # Main class configuration
5
+ # This class is the core of extend_at
4
6
  class Configuration
7
+ #
5
8
  def run(env=nil,model=nil)
6
9
  if env.kind_of? Hash
7
10
  hash = expand_options env, { :not_call_symbol => [:boolean], :not_expand => [:validate, :default] }, model.clone
8
11
  hash[:columns] = init_columns hash[:columns]
9
- return hash
12
+ @config = hash
13
+ read_associations_configuration
14
+ return @config
10
15
  end
11
16
 
12
17
  if not env.kind_of? Proc
@@ -17,6 +22,78 @@ module ExtendModelAt
17
22
  end
18
23
 
19
24
  protected
25
+ # Read all model relationships like belongs_to and has_many
26
+ def read_associations_configuration
27
+ [:has_one, :has_many, :belongs_to].each do |relation|
28
+ if @config.keys.include? :"#{relation}"
29
+ raise "Invalid #{relation} value" if not [Hash, Array, Symbol].include? @config[:"#{relation}"].class
30
+
31
+ # We change the user format (Hash, Array or only one element) to Array
32
+ if @config[:"#{relation}"].kind_of? Hash
33
+ list_models = @config[:"#{relation}"].keys
34
+ elsif @config[:"#{relation}"].kind_of? Array
35
+ list_models = @config[:"#{relation}"]
36
+ # Transform the array of model in a hash with his configuraion (empty, default values)
37
+ @config[:"#{relation}"] = {}
38
+ list_models.each do |model|
39
+ @config[:"#{relation}"][model.to_sym] = {}
40
+ end
41
+ else
42
+ list_models = [@config[:"#{relation}"]]
43
+ # Transform the array of model in a hash with his configuraion (empty, default values)
44
+ @config[:"#{relation}"] = {}
45
+ list_models.each do |model|
46
+ @config[:"#{relation}"][model.to_sym] = {}
47
+ end
48
+ end
49
+
50
+ # Iterate inside the array and get and create the configuration to that relationship
51
+ list_models.each do |model|
52
+ # If the user set some configuration (:class_name for example), we use it
53
+ if @config[:"#{relation}"][model.to_sym].kind_of? Hash
54
+ config = @config[:"#{relation}"][model.to_sym]
55
+ # If not, we create it
56
+ else
57
+ # Change sybol of the class name to hash configuration
58
+ @config[:"#{relation}"][model.to_sym] = {}
59
+ config = {}
60
+ end
61
+
62
+ # We set the default class_name if is not seted
63
+ if config[:class_name].nil?
64
+ @config[:"#{relation}"][model.to_sym][:class_name] = model.to_s.classify
65
+ else
66
+ @config[:"#{relation}"][model.to_sym][:class_name] = config[:class_name]
67
+ end
68
+
69
+ # If the association is belongs_to, we need to define the columns
70
+ if relation.to_s == "belongs_to"
71
+ if config[:polymorphic] == true
72
+ @config[:columns][ :"#{model}_id" ] = { :type => :integer }
73
+ @config[:columns][ :"#{model}_type" ] = { :type => :string }
74
+ else
75
+ @config[:columns][ config[:foreign_key] || :"#{model}_id" ] = { :type => :integer }
76
+ @config[:"#{relation}"][model.to_sym][:foreign_key] = config[:foreign_key] || :"#{model}_id" if @config[:"#{relation}"][model.to_sym][:foreign_key].nil?
77
+ end
78
+ end
79
+ # TODO: Continue adding rails features like:
80
+ # :autosave
81
+ # :class_name
82
+ # :conditions
83
+ # :counter_cache
84
+ # :dependent
85
+ # :foreign_key
86
+ # :include
87
+ # :polymorphic
88
+ # :readonly
89
+ # :select
90
+ # :touch
91
+ # :validate
92
+ end
93
+ end
94
+ end
95
+ end
96
+
20
97
  def init_columns(columns={})
21
98
  new = {}
22
99
  columns.each do |column, config|
@@ -40,7 +117,9 @@ module ExtendModelAt
40
117
  return :datetime if type == 'Date'
41
118
  return :any
42
119
  end
43
-
120
+
121
+ # Transform the user configuration to hash. For example, if the user use lambda to create the configuration, this function execute the lambda to get the result
122
+ # and re-parse it (and so on) to get a full hash configuration
44
123
  def expand_options(options={}, opts={}, model=nil)
45
124
  options = get_value_of options, model
46
125
  config_opts = {
@@ -66,6 +145,9 @@ module ExtendModelAt
66
145
  end
67
146
  end
68
147
 
148
+ # Return the value of the execute a function inside the model, for example:
149
+ # :column => :function
150
+ # this function execute the function _function_ to get the value and set it his return to column
69
151
  def get_value_of(value, model=nil)
70
152
  if value.kind_of? Symbol
71
153
  # If the function exist, we execute it
@@ -87,8 +87,75 @@ module ExtendModelAt
87
87
  def to_hash
88
88
  all_hash
89
89
  end
90
+
91
+ ##########
92
+ # Model associations
93
+ def read_belongs_to(model_name, configuration,force_reload=false)
94
+ if @config[:"belongs_to"][model_name.to_sym].kind_of? Hash
95
+ column = @config[:"belongs_to"][model_name.to_sym][:foreign_key] || :"#{model_name}_id"
96
+ else
97
+ column = :"#{model_name}_id"
98
+ end
99
+ class_name = @config[:"belongs_to"][model_name.to_sym][:class_name]
100
+ type = get_type column
101
+ type_class = get_type_class type
102
+
103
+ # We try to get the model
104
+ # eval "User.find(...try(:first).try(:id))"
105
+ eval "#{class_name}.find(#{get_value(column)})"
106
+
107
+ end
108
+
109
+ def read_has_many(model_name, configuration,force_reload=false)
110
+ Object
111
+ end
112
+
113
+ def read_has_one(model_name, configuration,force_reload=false)
114
+ Object
115
+ end
116
+
117
+ def write_belongs_to(model_name, configuration,associate)
118
+ puts "Warnig: Dummy function"
119
+ end
120
+
121
+ # TODO: I have problems to create a temporal model
122
+ def build_belongs_to(model_name, configuration,attributes)
123
+ puts "Warnig: Dummy function"
124
+ # config = @config[:"belongs_to"][model_name.to_sym]
125
+ #
126
+ # type = get_type(config[:foreign_key] || :"#{model_name}_id")
127
+ # type_class = get_type_class type
128
+ # return if type.nil?
129
+ # # We create the model and save it
130
+ # new_model = eval "#{config[:class_name]}.new(#{attributes})"
131
+ #
132
+ # # Set the model id in the correct column
133
+ # assign(config[:foreign_key] || :"#{model_name.to_s.underscore}_id", new_model.id)
134
+ end
135
+
136
+ # Create a belongs_to relationship
137
+ # Executed when the user use, for example, Post.create_comment :title => "Bla bla", :comment => "Comment ..."
138
+ # * _model_name_: Model class name
139
+ # * _configuration_: Relationship configuration like __;foreign_key__
140
+ # * _attributes_: Attributes to set to the new model
141
+ def create_belongs_to(model_name, configuration = {},attributes = {})
142
+ config = @config[:"belongs_to"][model_name.to_sym]
143
+
144
+ type = get_type(config[:foreign_key] || :"#{model_name}_id")
145
+ type_class = get_type_class type
146
+ return if type.nil?
147
+ # We create the model and save it
148
+ new_model = eval "#{config[:class_name]}.new(#{attributes})"
149
+ return false if not new_model.save
150
+
151
+ # Set the model id in the correct column
152
+ assign(config[:foreign_key] || :"#{model_name.to_s.underscore}_id", new_model.id)
153
+ end
154
+
155
+ ##### Model associations #####
90
156
 
91
157
  protected
158
+
92
159
  def get_column_model(column)
93
160
  type = get_type column
94
161
  type_class = get_type_class type
@@ -1,3 +1,3 @@
1
1
  module ExtendModelAt
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.3"
3
3
  end
data/lib/extend_at.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ require "active_support"
2
3
  require "extend_at/version"
3
4
  # require "extend_at/configuration"
4
5
  require "extend_at/model_manager"
@@ -28,7 +29,7 @@ module ExtendModelAt
28
29
  @columns = @configuration[:columns]
29
30
  @value = get_defaults_values @configuration
30
31
 
31
- # define_associations
32
+ define_associations
32
33
 
33
34
  initialize_values
34
35
  end
@@ -91,34 +92,85 @@ module ExtendModelAt
91
92
  @configuration = value
92
93
  end
93
94
 
94
- def define_associationss
95
+ def define_associations
95
96
  [:has_one, :has_many, :belongs_to].each do |relation|
96
- eval <<-EOS
97
- if @configuration.keys.include? :#{relation}
98
- raise "Invalid #{relation} value" if not [Hash, Array, NilClass].include? @configuration[:#{relation}].class
99
- # We nee an array of models, then, we
100
- if @configuration[:#{relation}].kind_of? Hash
101
- list_models = @configuration[:#{relation}].keys
102
- elsif @configuration[:#{relation}].kind_of? Array
103
- list_models = @configuration[:#{relation}]
104
- else
105
- list_models = [@configuration[:#{relation}]]
106
- end
107
- list_models.each do |model|
108
- define_method(model.to_sym) do |force_reload|
109
- if @configuration[:#{relation}].kind_of? Hash
110
- config = @configuration[:#{relation}][model]
97
+ if @configuration.keys.include? :"#{relation}"
98
+ raise "Invalid #{relation} value" if not [Hash, Array, Symbol].include? @configuration[:"#{relation}"].class
99
+ # We nee an array of models, then, we
100
+ if @configuration[:"#{relation}"].kind_of? Hash
101
+ list_models = @configuration[:"#{relation}"].keys
102
+ elsif @configuration[:"#{relation}"].kind_of? Array
103
+ list_models = @configuration[:"#{relation}"]
104
+ else
105
+ list_models = [@configuration[:"#{relation}"]]
106
+ end
107
+ list_models.each do |model|
108
+ meta_def model.to_s do |force_reload=false|
109
+ if @configuration[:"#{relation}"].kind_of? Hash
110
+ config = @configuration[:"#{relation}"][model]
111
+ else
112
+ config = {}
113
+ end
114
+ eval "@model_manager.read_#{relation} model, config, force_reload"
115
+ end
116
+
117
+ if "#{relation}" != "has_many"
118
+ meta_def "#{model.to_s}=" do |associate|
119
+ if @configuration[:"#{relation}"].kind_of? Hash
120
+ config = @configuration[:"#{relation}"][model]
111
121
  else
112
122
  config = {}
113
123
  end
114
- @model_manager.read_#{relation} model, @configuration[:#{relation}][model], force_reload
124
+ eval "@model_manager.write_#{relation} model, @configuration[:#{relation}][model], associate"
125
+ true
126
+ end
127
+
128
+ meta_def "build_#{model.to_s}" do |attributes={}|
129
+ if @configuration[:"#{relation}"].kind_of? Hash
130
+ config = @configuration[:"#{relation}"][model]
131
+ else
132
+ config = {}
133
+ end
134
+ eval "@model_manager.build_#{relation} model, config, attributes"
135
+ true
136
+ end
137
+
138
+ meta_def "create_#{model.to_s}" do |attributes={}|
139
+ if @configuration[:"#{relation}"].kind_of? Hash
140
+ config = @configuration[:"#{relation}"][model]
141
+ else
142
+ config = {}
143
+ end
144
+ eval "@model_manager.create_#{relation} model, config, attributes"
145
+ true
115
146
  end
116
147
  end
117
148
  end
118
- EOS
149
+ end
119
150
  end
120
151
  end
121
152
 
153
+ ##########
154
+ # Meta functions
155
+
156
+ def metaclass
157
+ class << self; self; end;
158
+ end
159
+
160
+ def meta_eval(&blk)
161
+ metaclass.instance_eval &blk
162
+ end
163
+
164
+ def meta_def(name, &blk)
165
+ meta_eval { define_method name, &blk }
166
+ end
167
+
168
+ def class_def name, &blk
169
+ class_eval { define_method name, &blk }
170
+ end
171
+
172
+ ##### Meta functions #####
173
+
122
174
  def get_adapter(column, value)
123
175
  if @columns[column.to_sym][:type] == String
124
176
  return :to_s
@@ -106,27 +106,38 @@ describe 'extend_at' do
106
106
  end
107
107
  end
108
108
 
109
- # context "associations support" do
110
- # context "belongs_to" do
111
- # it "simple usage" do
112
- # box = Toolbox.new
113
- # box.save
114
- # box.extra.create_tool
115
- # box.extra.tools.first.extra.toolbox.should == box
116
- # end
117
- # end
118
- #
119
- # context "has_many" do
120
- # context "simple usage" do
121
- # box = Toolbox.new
122
- # box.save
123
- # box.extra.create_tool
124
- # box.extra.create_tool
125
- # box.extra.create_tool
126
- # box.extra.tools.class.should == Array
127
- # box.extra.tools.size.should == 3
128
- # box.extra.tools.first.extra.toolbox.should == box
129
- # end
130
- # end
131
- # end
109
+ context "associations support" do
110
+ context "belongs_to" do
111
+ it "simple usage" do
112
+ tool = Tool.new
113
+ tool.extra.name = "Hammer"
114
+ tool.save
115
+ tool.extra.respond_to?(:create_toolbox).should == true
116
+ tool.extra.create_toolbox(:name => "Toolbox").should == true
117
+ tool.extra.toolbox.class.should == Toolbox
118
+ tool.extra.toolbox.name.should == "Toolbox"
119
+ end
120
+ end
121
+
122
+ context "has_many" do
123
+ it "simple usage" do
124
+ pending "Working on it"
125
+ tool = Tool.new
126
+ tool.extra.name = "Hammer"
127
+ tool.save
128
+ tool.extra.respond_to?(:create_toolbox).should == true
129
+ tool.extra.create_toolbox.should == true
130
+ tool.extra.create_toolbox.should == true
131
+ tool.extra.toolbox.class.should == Toolbox
132
+ box = Toolbox.new
133
+ box.save
134
+ box.extra.create_tool
135
+ box.extra.create_tool
136
+ box.extra.create_tool
137
+ box.extra.tools.class.should == Array
138
+ box.extra.tools.size.should == 3
139
+ box.extra.tools.first.extra.toolbox.should == box
140
+ end
141
+ end
142
+ end
132
143
  end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,7 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'rspec'
4
+
1
5
  require 'database_cleaner/active_record/base'
2
6
  require 'database_cleaner'
3
7
 
@@ -7,6 +11,11 @@ require 'app/config/environment'
7
11
  require 'rubygems'
8
12
  require 'bundler/setup'
9
13
 
14
+ require 'extend_at'
15
+
16
+
17
+ # Bundler.require(:default)
18
+
10
19
 
11
20
  RSpec.configure do |config|
12
21
  # config.before(:suite) do
@@ -21,4 +30,3 @@ RSpec.configure do |config|
21
30
  # DatabaseCleaner.clean
22
31
  # end
23
32
  end
24
-
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: extend_at
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-25 00:00:00.000000000 Z
12
+ date: 2012-06-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
- requirement: &6926540 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,40 +21,92 @@ dependencies:
21
21
  version: '3.1'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *6926540
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '3.1'
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: rspec
27
- requirement: &6925900 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ~>
31
36
  - !ruby/object:Gem::Version
32
- version: '2.5'
37
+ version: '2.8'
33
38
  type: :development
34
39
  prerelease: false
35
- version_requirements: *6925900
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '2.8'
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: rspec-core
38
- requirement: &6925520 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '2.8'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.8'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec-expectations
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '2.8'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
39
73
  none: false
40
74
  requirements:
41
- - - ! '>='
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '2.8'
78
+ - !ruby/object:Gem::Dependency
79
+ name: activesupport
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
42
84
  - !ruby/object:Gem::Version
43
- version: '0'
85
+ version: '3.1'
44
86
  type: :development
45
87
  prerelease: false
46
- version_requirements: *6925520
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '3.1'
47
94
  - !ruby/object:Gem::Dependency
48
95
  name: database_cleaner
49
- requirement: &5741880 !ruby/object:Gem::Requirement
96
+ requirement: !ruby/object:Gem::Requirement
50
97
  none: false
51
98
  requirements:
52
99
  - - ~>
53
100
  - !ruby/object:Gem::Version
54
- version: '0.7'
101
+ version: '0.8'
55
102
  type: :development
56
103
  prerelease: false
57
- version_requirements: *5741880
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: '0.8'
58
110
  description: ! 'This gem allows you to extend rails models without migrations: This
59
111
  way you can, i.e., develop your own content types, like in Drupal.'
60
112
  email:
@@ -211,7 +263,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
211
263
  version: '0'
212
264
  requirements: []
213
265
  rubyforge_project: extend_at
214
- rubygems_version: 1.8.11
266
+ rubygems_version: 1.8.24
215
267
  signing_key:
216
268
  specification_version: 3
217
269
  summary: Create dynamic fields to extend rails models (like content types in Drupal)