extend_at 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -2,3 +2,8 @@ source "http://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in acts_as_configuration.gemspec
4
4
  gemspec
5
+
6
+
7
+ group :test do
8
+ gem "rails", "~> 3.1.0"
9
+ end
data/README.markdown CHANGED
@@ -8,16 +8,21 @@ This gem allows you to extend models without migrations: This way you can, i.e.,
8
8
 
9
9
  ### Rails 3
10
10
  Add in your Gemfile:
11
+
11
12
  <code>gem 'extend_at'</code>
12
13
 
14
+ After that, you need execute:
15
+
16
+ <code>rails generate extend_at:install</code>
17
+
18
+ This will generate one migration with all necessary tables.
19
+
13
20
  ## Usage
14
21
 
15
- You only need to add the next line in your model.
22
+ You don't need an extra column in your model. Only you need is put next code in your model.
16
23
 
17
24
  <code>extend_at :extra</code>
18
25
 
19
- The column <code>extra</code> must be string or text.
20
-
21
26
  For example:
22
27
 
23
28
  class User < ActiveRecord::Base
@@ -80,6 +85,33 @@ You can set the colum's type.
80
85
  end
81
86
  end
82
87
 
88
+ ##### Valid types
89
+
90
+ Valid symbols:
91
+
92
+ * <code>:any</code>
93
+ * <code>:binary</code>
94
+ * <code>:boolean</code>
95
+ * <code>:date</code>
96
+ * <code>:datetime</code>
97
+ * <code>:decimal</code>
98
+ * <code>:float</code>
99
+ * <code>:integer</code>
100
+ * <code>:string</code>
101
+ * <code>:text</code>
102
+ * <code>:time</code>
103
+ * <code>:timestamp</code>
104
+
105
+ But you can use classes.
106
+
107
+ * Float: <code>:any</code>
108
+ * Fixnum: <code>:integer</code>
109
+ * String: <code>:text</code>
110
+ * Time: <code>:timestamp</code>
111
+ * Date: <code>:datetime</code>
112
+
113
+ Else, return <code>:any</code>
114
+
83
115
  You can use any class, but if you need use boolean values, you must use :boolean.
84
116
 
85
117
  #### Set default value
@@ -133,8 +165,8 @@ You can use any class, but if you need use boolean values, you must use :boolean
133
165
  :default => 1,
134
166
  :validate => lambda {
135
167
  |age|
136
- errors.add :config_age, "Are you Matusalen?" if age > 150
137
- errors.add :config_age, "Are you a fetus?" if age <= 0
168
+ errors.add :extra_age, "Are you Matusalen?" if age > 150
169
+ errors.add :extra_age, "Are you a fetus?" if age <= 0
138
170
  }
139
171
  }, :profile_description => {
140
172
  :type => lambda {
@@ -149,7 +181,7 @@ You can use any class, but if you need use boolean values, you must use :boolean
149
181
  },
150
182
  :validate => lambda {
151
183
  |time|
152
- errors.add :config_last_loggin, "You can't loggin on the future" if time > Time.now
184
+ errors.add :extra_last_loggin, "You can't loggin on the future" if time > Time.now
153
185
  }
154
186
  }, :subscribe_to_rss => :get_rss_config
155
187
  }
@@ -179,9 +211,28 @@ You can use any class, but if you need use boolean values, you must use :boolean
179
211
  end
180
212
  end
181
213
 
214
+ ### Scopes
215
+
216
+ You can use scope like:
217
+
218
+ User.extra_last_loggin_gt_eq(1.week.ago).extra_age_gt_eq(18).where(:column => "value").all
219
+
220
+ Valid scopes:
221
+
222
+ <extention>_<column_name>_<comparation>
223
+
224
+ Comparations:
225
+
226
+ * lt
227
+ * lt_eq
228
+ * eq
229
+ * gt_eq
230
+ * gt
231
+ * match
232
+
182
233
  ### Integration in the views
183
234
 
184
- If you like to use some configuration variable in your views you only need put the name of the input like <code>:config_name</code>, for example:
235
+ 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:
185
236
 
186
237
  <% form_for(@user) do |f| %>
187
238
  ...
@@ -227,6 +278,11 @@ This code read the configuration of the columns when you access to the extra col
227
278
 
228
279
  If you found a bug, create an issue. If you have a recomendation, idea, etc., create a request or fork the project.
229
280
 
281
+ ## TODO:
282
+
283
+ * RSpec test
284
+ * Support static columns
285
+
230
286
  ## License
231
287
 
232
288
  This gem is under MIT license.
data/Rakefile CHANGED
@@ -1 +1,12 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+ require 'rspec'
4
+ require 'rspec/core/rake_task'
5
+
6
+
7
+ task :default => :spec
8
+ task :test => :spec
9
+
10
+ RSpec::Core::RakeTask.new(:spec) do
11
+ system "echo \"recreating database \" && cd #{File.join(File.dirname(__FILE__), 'spec', 'app')} && rake db:migrate:reset"
12
+ end
data/extend_at.gemspec CHANGED
@@ -18,5 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
- s.add_development_dependency "rspec"
21
+ s.add_runtime_dependency 'rails', '~> 3.1'
22
+ s.add_development_dependency "rspec", '~> 2.5'
23
+ s.add_development_dependency "rspec-core"
22
24
  end
@@ -0,0 +1,136 @@
1
+ require File.expand_path('../models/all', __FILE__)
2
+
3
+ module ExtendModelAt
4
+ class ModelManager
5
+ def initialize(column_name,model, config)
6
+ @column_name, @model, @config = column_name, model, config
7
+
8
+ if not @model.new_record?
9
+ @extend_at = ExtendAt.find_by_model_id_and_model_type @model.id, @model.class.to_s
10
+ else
11
+ @extend_at = ExtendAt.new
12
+ @extend_at.save
13
+ end
14
+ end
15
+
16
+ def assign(column,value)
17
+ raise "#{value} is not valid" if not @model.send(:valid_type?, value, @config[column.to_sym].try(:[], :type))
18
+
19
+ last_model = get_column_model column
20
+ type_class = get_type_class @config[column.to_sym].try(:[], :type)
21
+
22
+ if last_model.nil?
23
+ eval "
24
+ new_column = Column.new :extend_at_id => @extend_at.id
25
+ new_column.save
26
+ new_value = #{type_class}.new(:column => column, :value => value, :extend_at_column_id => new_column.id)
27
+ new_value.save
28
+ new_column.column_id = new_value.id
29
+ new_column.save
30
+ "
31
+ else
32
+ eval "last_model.value = value
33
+ last_model.save"
34
+ end
35
+ end
36
+
37
+ def get_value(column)
38
+ model = get_column_model column #, get_type(column)
39
+ model.try(:value)
40
+ end
41
+
42
+ protected
43
+ def get_column_model(column)
44
+ type = get_type column
45
+ type_class = get_type_class type
46
+ eval "::#{type_class}.where(
47
+ ::#{type_class}.arel_table[:column].eq(column).and(
48
+ ::#{type_class}.arel_table[:extend_at_column_id].in(
49
+ ::Column.arel_table.project(:id).where(
50
+ ::Column.arel_table[:extend_at_id].eq(@extend_at.id)
51
+ )
52
+ )
53
+ )
54
+ ).try(:first)"
55
+ end
56
+
57
+ def get_type(column)
58
+ if @config[column.to_sym].kind_of? Hash
59
+ @config[column.to_sym][:type]
60
+ else
61
+ nil
62
+ end
63
+ end
64
+
65
+ def get_type_class(type)
66
+ type = type
67
+ if type == :any or type.nil?
68
+ return "AnyValue"
69
+ elsif type == :binary
70
+ return "BinaryValue"
71
+ elsif type == :boolean
72
+ return "BooleanValue"
73
+ elsif type == :date
74
+ return "DateValue"
75
+ elsif type == :datetime
76
+ return "DatetimeValue"
77
+ elsif type == :decimal
78
+ return "DecimalValue"
79
+ elsif type == :float
80
+ return "FloatValue"
81
+ elsif type == :integer
82
+ return "IntegerValue"
83
+ elsif type == :string
84
+ return "StringValue"
85
+ elsif type == :text
86
+ return "TextValue"
87
+ elsif type == :time
88
+ return "TimeValue"
89
+ elsif type == :timestamp
90
+ return "TimestampValue"
91
+ else
92
+ return "AnyValue"
93
+ end
94
+ end
95
+
96
+ def update
97
+ @extend_at.model_id = @model.id
98
+ @extend_at.model_type = @model.class.to_s
99
+ @extend_at.save
100
+ end
101
+
102
+ EQUIVALENCE_METHODS = {
103
+ 'lt' => 'lt',
104
+ 'lt_eq' => 'lteq',
105
+ 'eq' => 'eq',
106
+ 'gt' => 'gt',
107
+ 'gt_eq' => 'gteq',
108
+ 'match' => 'matches'
109
+ }
110
+
111
+ def search(column, method,value)
112
+ type = get_type column
113
+ type_class = get_type_class type
114
+ equivalence_method = EQUIVALENCE_METHODS[method.to_s]
115
+ "
116
+ where(
117
+ ExtendAt.arel_table.project('model_id').where(
118
+ ExtendAt.arel_table[:model_type].eq(\"#{@model.class.name}\").and(
119
+ ExtendAt.arel_table[:id].in(
120
+ ::Column.arel_table.project('extend_at_id').where(
121
+ ::Column.arel_table[:id].in(
122
+ ::#{type_class}.arel_table.project('extend_at_column_id').where(
123
+ ::#{type_class}.arel_table[:column].eq(column).and(
124
+ ::#{type_class}.arel_table[:value].#{equivalence_method}(value)
125
+ )
126
+ )
127
+ )
128
+ )
129
+ )
130
+ )
131
+ ).to_sql
132
+ )
133
+ "
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,15 @@
1
+ require File.expand_path('../any_value', __FILE__)
2
+ require File.expand_path('../string_value', __FILE__)
3
+ require File.expand_path('../text_value', __FILE__)
4
+ require File.expand_path('../integer_value', __FILE__)
5
+ require File.expand_path('../float_value', __FILE__)
6
+ require File.expand_path('../decimal_value', __FILE__)
7
+ require File.expand_path('../datetime_value', __FILE__)
8
+ require File.expand_path('../timestamp_value', __FILE__)
9
+ require File.expand_path('../time_value', __FILE__)
10
+ require File.expand_path('../date_value', __FILE__)
11
+ require File.expand_path('../binary_value', __FILE__)
12
+ require File.expand_path('../boolean_value', __FILE__)
13
+
14
+ require File.expand_path('../column', __FILE__)
15
+ require File.expand_path('../extend_at', __FILE__)
@@ -0,0 +1,5 @@
1
+ class AnyValue < ActiveRecord::Base
2
+ set_table_name "extend_at_anies"
3
+ belongs_to :extend_at_column, :class_name => 'Column', :foreign_key => 'extend_at_column_id'
4
+ end
5
+
@@ -0,0 +1,4 @@
1
+ class BinaryValue < ActiveRecord::Base
2
+ set_table_name "extend_at_binaries"
3
+ belongs_to :extend_at_column, :class_name => 'Column', :foreign_key => 'extend_at_column_id'
4
+ end
@@ -0,0 +1,4 @@
1
+ class BooleanValue < ActiveRecord::Base
2
+ set_table_name "extend_at_booleans"
3
+ belongs_to :extend_at_column, :class_name => 'Column', :foreign_key => 'extend_at_column_id'
4
+ end
@@ -0,0 +1,10 @@
1
+ class Column < ActiveRecord::Base
2
+ set_table_name "extend_at_columns"
3
+ # belongs_to :extend_at
4
+ belongs_to :column, :polymorphic => true
5
+ belongs_to :extend_at, :class_name => 'ExtendAt'
6
+ scope :for_model, lambda { |model|
7
+ where(:model_id => model.try(:id) || model.to_i)
8
+ }
9
+ end
10
+
@@ -0,0 +1,4 @@
1
+ class DateValue < ActiveRecord::Base
2
+ set_table_name "extend_at_dates"
3
+ belongs_to :extend_at_column, :class_name => 'Column', :foreign_key => 'extend_at_column_id'
4
+ end
@@ -0,0 +1,4 @@
1
+ class DatetimeValue < ActiveRecord::Base
2
+ set_table_name "extend_at_datetimes"
3
+ belongs_to :extend_at_column, :class_name => 'Column', :foreign_key => 'extend_at_column_id'
4
+ end
@@ -0,0 +1,4 @@
1
+ class DecimalValue < ActiveRecord::Base
2
+ set_table_name "extend_at_decimals"
3
+ belongs_to :extend_at_column, :class_name => 'Column', :foreign_key => 'extend_at_column_id'
4
+ end
@@ -0,0 +1,6 @@
1
+ class ExtendAt < ActiveRecord::Base
2
+ set_table_name "extend_ats"
3
+ belongs_to :model, :polymorphic => true
4
+ has_many :extend_at_columns, :source => :extend_at, :class_name => 'Column'
5
+ # has_many :columns, :through => :extend_at_columns, :source => :column
6
+ end
@@ -0,0 +1,4 @@
1
+ class FloatValue < ActiveRecord::Base
2
+ set_table_name "extend_at_floats"
3
+ belongs_to :extend_at_column, :class_name => 'Column', :foreign_key => 'extend_at_column_id'
4
+ end
@@ -0,0 +1,4 @@
1
+ class IntegerValue < ActiveRecord::Base
2
+ set_table_name "extend_at_integers"
3
+ belongs_to :extend_at_column, :class_name => 'Column', :foreign_key => 'extend_at_column_id'
4
+ end
@@ -0,0 +1,5 @@
1
+ class StringValue < ActiveRecord::Base
2
+ set_table_name "extend_at_strings"
3
+ belongs_to :extend_at_column, :class_name => 'Column', :foreign_key => 'extend_at_column_id'
4
+ end
5
+
@@ -0,0 +1,5 @@
1
+ class TextValue < ActiveRecord::Base
2
+ set_table_name "extend_at_texts"
3
+ belongs_to :extend_at_column, :class_name => 'Column', :foreign_key => 'extend_at_column_id'
4
+ end
5
+
@@ -0,0 +1,4 @@
1
+ class TimeValue < ActiveRecord::Base
2
+ set_table_name "extend_at_times"
3
+ belongs_to :extend_at_column, :class_name => 'Column', :foreign_key => 'extend_at_column_id'
4
+ end
@@ -0,0 +1,4 @@
1
+ class TimestampValue < ActiveRecord::Base
2
+ set_table_name "extend_at_timestamps"
3
+ belongs_to :extend_at_column, :class_name => 'Column', :foreign_key => 'extend_at_column_id'
4
+ end
@@ -1,3 +1,3 @@
1
1
  module ExtendModelAt
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/extend_at.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # encoding: utf-8
2
2
  require "extend_at/version"
3
+ require "extend_at/model_manager"
4
+ require "extend_at/models/all"
3
5
 
4
6
  module ExtendModelAt
5
7
  def self.included(base)
@@ -13,6 +15,7 @@ module ExtendModelAt
13
15
  @column_name = options[:column_name].to_s
14
16
  @columns = options[:columns]
15
17
  @value = get_defaults_values options
18
+ @model_manager = ::ExtendModelAt::ModelManager.new(@column_name, @model, @columns)
16
19
 
17
20
  raise "#{@column_name} should by text or string not #{options[:model].column_for_attribute(@column_name.to_sym).type}" if not [:text, :stiring].include? options[:model].column_for_attribute(@column_name.to_sym).type
18
21
 
@@ -26,21 +29,31 @@ module ExtendModelAt
26
29
 
27
30
  initialize_values
28
31
 
32
+
29
33
  @model.attributes[@column_name] = @value
30
- @model.save(:validate => false)
31
34
  end
32
35
 
33
36
  def [](key)
34
- @value[key.to_s]
37
+ @model_manager.get_value(key)
35
38
  end
36
39
 
37
40
  def []=(key, value)
38
- if @columns[key.to_sym].kind_of? Hash and ((@columns[key.to_sym][:type] == :boolean and (not [true.class, false.class].include? value.class)) or
39
- ((not [:boolean, nil].include?(@columns[key.to_sym][:type])) and @columns[key.to_sym][:type] != value.class ))
40
- raise "#{value.inspect} is not a valid type, expected #{@columns[key.to_sym][:type]}"
41
+ if not valid_type? value, @columns[key.to_sym].try(:[],:type)
42
+ # Try to adapt the value
43
+ adapter = get_adapter key, value
44
+ raise "#{value.inspect} is not a valid type, expected #{@columns[key.to_sym][:type]}" if adapter.nil? # We can't adapt the value
45
+ value = value.send adapter
41
46
  end
42
47
  @value[key.to_s] = value
43
- @model.send :"#{@column_name}=", @value.to_yaml
48
+ @model_manager.assign(key,value)
49
+ end
50
+
51
+ def self.respond_to?(symbol, include_private=false)
52
+ true
53
+ end
54
+
55
+ def respond_to?(symbol, include_private=false)
56
+ true
44
57
  end
45
58
 
46
59
  # Use the undefined method as a column
@@ -57,6 +70,21 @@ module ExtendModelAt
57
70
 
58
71
  private
59
72
 
73
+ def get_adapter(column, value)
74
+ if @columns[column.to_sym][:type] == String
75
+ return :to_s
76
+ elsif @columns[column.to_sym][:type] == Fixnum
77
+ return :to_i if value.respond_to? :to_i
78
+ elsif @columns[column.to_sym][:type] == Float
79
+ return :to_f if value.respond_to? :to_f
80
+ elsif @columns[column.to_sym][:type] == Time
81
+ return :to_time if value.respond_to? :to_time
82
+ elsif @columns[column.to_sym][:type] == Date
83
+ return :to_date if value.respond_to? :to_date
84
+ end
85
+ nil
86
+ end
87
+
60
88
  def initialize_values
61
89
  if not @value.kind_of? Hash
62
90
  @model.attributes[@column_name] = {}.to_yaml
@@ -71,6 +99,18 @@ module ExtendModelAt
71
99
  end
72
100
  defaults_
73
101
  end
102
+
103
+ def update_model_manager
104
+ @model_manager.send :update
105
+ end
106
+
107
+ def valid_type?(value, type)
108
+ @model.send :valid_type?, value, type
109
+ end
110
+
111
+ def search(column, method, value)
112
+ @model_manager.send:search, column, method, value
113
+ end
74
114
  end
75
115
 
76
116
  module ClassMethods
@@ -104,7 +144,6 @@ module ExtendModelAt
104
144
  def []=(column, value)
105
145
  if column.to_s =~ /^#{column_name}_[a-zA-Z_][a-zA-Z_0-9]*\=?$/
106
146
  rb = \"self.#{column_name}.\#\{column.to_s.gsub(/^#{column_name}_/,'').gsub(/\=$/, '')\} = value\"
107
- puts \"Evaluando: #\{rb}\"
108
147
  eval rb, binding
109
148
  else
110
149
  super
@@ -120,9 +159,37 @@ module ExtendModelAt
120
159
  end
121
160
  end
122
161
 
162
+ # Respond to ethod like <column name>_<extended column name> for read or write
163
+ def respond_to?(symbol, include_private=false)
164
+ if symbol.to_s =~ /^#{column_name}_[a-zA-Z_][a-zA-Z_0-9]*\=?$/
165
+ return true
166
+ else
167
+ super
168
+ end
169
+ end
170
+
171
+ def self.method_missing(m, *args, &block)
172
+ if m.to_s =~ /^#{column_name}_[a-zA-Z_][a-zA-Z_0-9]+_(#\{VALID_COMPARATIONS.join('|')})$/
173
+ method = m[/(#\{VALID_COMPARATIONS.join('|')})$/]
174
+ column = m.to_s.gsub(/^#{column_name}_/, '').gsub(/_(#\{VALID_COMPARATIONS.join('|')})$/, '')
175
+
176
+ code = (self.last || self.new).send :search_in_extention, column, method, args.first
177
+
178
+ value = args.first
179
+
180
+ return eval code, binding
181
+ else
182
+ super
183
+ end
184
+ end
185
+
123
186
  # Accept method like <column name>_<extended column name> for read or write
124
187
  def method_missing(m, *args, &block)
125
- if m.to_s =~ /^#{column_name}_[a-zA-Z_][a-zA-Z_0-9]*\=$/
188
+ if m.to_s =~ /^#{column_name}_[a-zA-Z_][a-zA-Z_0-9]+_(#\{VALID_COMPARATIONS.join('|')})$/
189
+ method = m[/(#\{VALID_COMPARATIONS.join('|')})$/]
190
+ column = m.to_s.gsub(/^#{column_name}_/, '').gsub(/(#\{VALID_COMPARATIONS.join('|')})/, '')
191
+ return search_in_extention column, method, args.first
192
+ elsif m.to_s =~ /^#{column_name}_[a-zA-Z_][a-zA-Z_0-9]*\=$/
126
193
  rb = \"self.#{column_name}.\#\{m.to_s.gsub(/^#{column_name}_/, '').gsub(/\=$/, '')} = args.first\"
127
194
  return eval rb, binding
128
195
  elsif m.to_s =~ /^#{column_name}_[a-zA-Z_][a-zA-Z_0-9]*$/
@@ -132,6 +199,13 @@ module ExtendModelAt
132
199
  super
133
200
  end
134
201
  end
202
+
203
+ protected
204
+ VALID_COMPARATIONS = ['gt', 'gt_eq', 'lt', 'lt_eq', 'eq', 'in', 'match']
205
+
206
+ def search_in_extention(column, method, value)
207
+ #{column_name.to_s}.send :search, column, method, value
208
+ end
135
209
  "
136
210
 
137
211
  self.class_eval <<-EOS
@@ -141,13 +215,14 @@ module ExtendModelAt
141
215
  class_eval <<-EOV
142
216
  public
143
217
  validate :extend_at_validations
218
+ after_save :update_model_manager, :on => :create
144
219
 
145
220
  def #{column_name.to_s}
146
221
  if not @#{column_name.to_s}_configuration.kind_of? ExtendModelAt::Extention
147
222
  opts = initialize_options(#{options})
148
223
  options = {
149
224
  :extensible => true # If is false, only the columns defined in :columns can be used
150
- }.merge! opts
225
+ }.merge!(opts)
151
226
  columns = initialize_columns expand_options(options, { :not_call_symbol => [:boolean], :not_expand => [:validate, :default] }) if options.kind_of? Hash
152
227
  @#{column_name.to_s}_configuration ||= ExtendModelAt::Extention.new({:model => self, :column_name => :#{column_name.to_s}, :columns => columns})
153
228
  end
@@ -155,6 +230,8 @@ module ExtendModelAt
155
230
  end
156
231
 
157
232
  protected
233
+ VALID_SYMBOLS = [:any, :binary, :boolean, :date, :datetime, :decimal, :float, :integer, :string, :text, :time, :timestamp]
234
+
158
235
  def extend_at_validations
159
236
  self.#{column_name}.valid?
160
237
  @extend_at_validation ||= {} if not @extend_at_validation.kind_of? Hash
@@ -198,16 +275,11 @@ module ExtendModelAt
198
275
  # Stablish the type
199
276
  if config[:type].class == Class
200
277
  # If exist :type, is a static column
278
+ column_config[:type] = get_type_for_class config[:type]
279
+ elsif config[:type].class == Symbol and VALID_SYMBOLS.include? config[:type]
201
280
  column_config[:type] = config[:type]
202
281
  else
203
- # if not, is a dynamic column
204
- if config[:type].to_sym == :any
205
- column_config[:type] = nil
206
- elsif config[:type].to_sym == :boolean
207
- column_config[:type] = :boolean
208
- else
209
- raise "\#\{config[:type]\} is not a valid column type"
210
- end
282
+ raise "\#\{config[:type]\} is not a valid column type"
211
283
  end
212
284
 
213
285
  # Stablish the default value
@@ -219,8 +291,7 @@ module ExtendModelAt
219
291
  else
220
292
  # If the column have a type, we verify the type
221
293
  if not column_config[:type].nil?
222
- if (column_config[:type] == :boolean and (not [true.class, false.class].include? config[:default].class)) or
223
- ((not [:boolean, nil].include?(column_config[:type])) and column_config[:type] != config[:default].class )
294
+ if not valid_type?(config[:default], column_config[:type])
224
295
  raise "The column \#\{column\} has an invalid default value. Expected \#\{column_config[:type]}, not \#\{config[:default].class}"
225
296
  end
226
297
  column_config[:default] = config[:default]
@@ -234,7 +305,7 @@ module ExtendModelAt
234
305
  if [Symbol, Proc].include? config[:validate].class
235
306
  column_config[:validate] = config[:validate]
236
307
  create_validation_for column, config[:validate]
237
- else
308
+ elsif not config[:validate].nil?
238
309
  raise "The validation of \#\{column\} is invalid"
239
310
  end
240
311
 
@@ -242,6 +313,18 @@ module ExtendModelAt
242
313
  column_config
243
314
  end
244
315
 
316
+ def get_type_from_symbol(type)
317
+ type = type.to_s
318
+ return nil if type == 'any' or type == ''
319
+ return :boolean if type == 'boolean'
320
+ return Float if type == 'float'
321
+ return Fixnum if type == 'integer'
322
+ return String if type == 'string' or type == 'text'
323
+ return Time if type == 'time' or type == 'timestamp'
324
+ return Date if type == 'date' or type == 'datetime'
325
+ return eval type.classify
326
+ end
327
+
245
328
  def create_validation_for(column, validation)
246
329
  column = column.to_sym
247
330
  @extend_at_validation ||= {}
@@ -249,6 +332,7 @@ module ExtendModelAt
249
332
  end
250
333
 
251
334
  def expand_options(options={}, opts={})
335
+ options = get_value_of options
252
336
  config_opts = {
253
337
  :not_expand => [],
254
338
  :not_call_symbol => []
@@ -287,6 +371,40 @@ module ExtendModelAt
287
371
  return value
288
372
  end
289
373
  end
374
+
375
+ def update_model_manager
376
+ self.#{column_name}.send :update_model_manager
377
+ end
378
+
379
+ def get_type_for_class(type)
380
+ type = type.name
381
+ return :any if type == 'NilClass'
382
+ return :float if type == 'Float'
383
+ return :integer if type == 'Fixnum'
384
+ return :text if type == 'String '
385
+ return :timestamp if type == 'Time'
386
+ return :datetime if type == 'Date'
387
+ return :any
388
+ end
389
+
390
+ def compatible_type(value,type)
391
+ return true if value.class == String and [:string, :text, :binary].include? type
392
+ return true if value.class == Fixnum and [:integer, :float].include? type
393
+ return true if [true.class, false.class].include? value.class and [:boolean].include? type
394
+ return true if value.class == BigDecimal and [:decimal].include? type
395
+ return true if [Date, Time].include? value.class and [:date, :time].include? type
396
+ return true if value.class == BigDecimal and [:decimal].include? type
397
+ return true if [Date, Time, ActiveSupport::TimeWithZone].include? value.class and [:datetime, :timestamp].include? type
398
+ false
399
+ end
400
+
401
+ def valid_type?(value, type)
402
+ type = type.to_s.to_sym
403
+ [:"", :any].include? type or
404
+ value.nil? or
405
+ (type == :boolean and ([true.class, false.class].include? value.class)) or
406
+ ((not [:boolean, nil].include?(type)) and not value.nil? and compatible_type(value, type))
407
+ end
290
408
  EOV
291
409
  end
292
410
  end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Install extend_at gem
3
+
4
+ Example:
5
+ rails generate extend_at:install
6
+
7
+ This will create:
8
+ db/migrate/extend_at_tables.rb
@@ -0,0 +1,22 @@
1
+ class ExtendAt::InstallGenerator < Rails::Generators::Base
2
+ include Rails::Generators::Migration
3
+ source_root File.expand_path('../templates', __FILE__)
4
+ desc "Generate all necesaries models and migrations for extend_at gem"
5
+ def install
6
+ create_model_file
7
+ end
8
+
9
+ def self.next_migration_number(path)
10
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
11
+ end
12
+
13
+ def create_model_file
14
+ # template "models/integer_value.rb", "app/models/integer_value.rb"
15
+ # template "models/float_value.rb", "app/models/float_value.rb"
16
+ # template "models/string_value.rb", "app/models/string_value.rb"
17
+ # template "models/text_value.rb", "app/models/text_value.rb"
18
+ # template "models/any_value.rb", "app/models/any_value.rb"
19
+ # template "models/column.rb", "app/models/column.rb"
20
+ migration_template "create_extend_at_tables.rb", "db/migrate/create_extend_at_tables.rb"
21
+ end
22
+ end
@@ -0,0 +1,102 @@
1
+ class CreateExtendAtTables < ActiveRecord::Migration
2
+ def up
3
+ create_table :extend_at_strings do |t|
4
+ t.belongs_to :extend_at_column
5
+ t.string :column
6
+ t.string :value
7
+ end
8
+
9
+ create_table :extend_at_texts do |t|
10
+ t.belongs_to :extend_at_column
11
+ t.string :column
12
+ t.text :value
13
+ end
14
+
15
+ create_table :extend_at_integers do |t|
16
+ t.belongs_to :extend_at_column
17
+ t.string :column
18
+ t.integer :value
19
+ end
20
+
21
+ create_table :extend_at_floats do |t|
22
+ t.belongs_to :extend_at_column
23
+ t.string :column
24
+ t.float :value
25
+ end
26
+
27
+ create_table :extend_at_decimals do |t|
28
+ t.belongs_to :extend_at_column
29
+ t.string :column
30
+ t.decimal :value
31
+ end
32
+
33
+ create_table :extend_at_datetimes do |t|
34
+ t.belongs_to :extend_at_column
35
+ t.string :column
36
+ t.datetime :value
37
+ end
38
+
39
+ create_table :extend_at_timestamps do |t|
40
+ t.belongs_to :extend_at_column
41
+ t.string :column
42
+ t.timestamp :value
43
+ end
44
+
45
+ create_table :extend_at_times do |t|
46
+ t.belongs_to :extend_at_column
47
+ t.string :column
48
+ t.time :value
49
+ end
50
+
51
+ create_table :extend_at_dates do |t|
52
+ t.belongs_to :extend_at_column
53
+ t.string :column
54
+ t.date :value
55
+ end
56
+
57
+ create_table :extend_at_binaries do |t|
58
+ t.belongs_to :extend_at_column
59
+ t.string :column
60
+ t.binary :value
61
+ end
62
+
63
+ create_table :extend_at_booleans do |t|
64
+ t.belongs_to :extend_at_column
65
+ t.string :column
66
+ t.boolean :value
67
+ end
68
+
69
+ create_table :extend_at_anies do |t|
70
+ t.belongs_to :extend_at_column
71
+ t.string :column
72
+ t.text :value
73
+ end
74
+
75
+ create_table :extend_ats do |t|
76
+ t.references :model, :polymorphic => true
77
+ end
78
+
79
+ create_table :extend_at_columns do |t|
80
+ t.belongs_to :extend_at
81
+ t.belongs_to :column, :polymorphic => true
82
+ end
83
+ end
84
+
85
+ def down
86
+ drop_table :extend_at_strings
87
+ drop_table :extend_at_texts
88
+ drop_table :extend_at_integers
89
+ drop_table :extend_at_floats
90
+ drop_table :extend_at_decimals
91
+ drop_table :extend_at_datetimes
92
+ drop_table :extend_at_timestamps
93
+ drop_table :extend_at_times
94
+ drop_table :extend_at_dates
95
+ drop_table :extend_at_binaries
96
+ drop_table :extend_at_booleans
97
+ drop_table :extend_at_anies
98
+
99
+ drop_table :extend_ats
100
+ drop_table :extend_at_columns
101
+ end
102
+ end
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.0.3
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,33 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-01 00:00:00.000000000 Z
12
+ date: 2012-01-10 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: &14819500 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.1'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *14819500
14
25
  - !ruby/object:Gem::Dependency
15
26
  name: rspec
16
- requirement: &10011740 !ruby/object:Gem::Requirement
27
+ requirement: &14799780 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '2.5'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *14799780
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec-core
38
+ requirement: &14799380 !ruby/object:Gem::Requirement
17
39
  none: false
18
40
  requirements:
19
41
  - - ! '>='
@@ -21,7 +43,7 @@ dependencies:
21
43
  version: '0'
22
44
  type: :development
23
45
  prerelease: false
24
- version_requirements: *10011740
46
+ version_requirements: *14799380
25
47
  description: ! 'This gem allows you to extend models without migrations: This way
26
48
  you can, i.e., develop your own content types, like in Drupal.'
27
49
  email:
@@ -37,7 +59,26 @@ files:
37
59
  - Rakefile
38
60
  - extend_at.gemspec
39
61
  - lib/extend_at.rb
62
+ - lib/extend_at/model_manager.rb
63
+ - lib/extend_at/models/all.rb
64
+ - lib/extend_at/models/any_value.rb
65
+ - lib/extend_at/models/binary_value.rb
66
+ - lib/extend_at/models/boolean_value.rb
67
+ - lib/extend_at/models/column.rb
68
+ - lib/extend_at/models/date_value.rb
69
+ - lib/extend_at/models/datetime_value.rb
70
+ - lib/extend_at/models/decimal_value.rb
71
+ - lib/extend_at/models/extend_at.rb
72
+ - lib/extend_at/models/float_value.rb
73
+ - lib/extend_at/models/integer_value.rb
74
+ - lib/extend_at/models/string_value.rb
75
+ - lib/extend_at/models/text_value.rb
76
+ - lib/extend_at/models/time_value.rb
77
+ - lib/extend_at/models/timestamp_value.rb
40
78
  - lib/extend_at/version.rb
79
+ - lib/generators/extend_at/USAGE
80
+ - lib/generators/extend_at/install_generator.rb
81
+ - lib/generators/extend_at/templates/create_extend_at_tables.rb
41
82
  homepage: ''
42
83
  licenses: []
43
84
  post_install_message: