extend_at 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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)