extend_at 0.0.3 → 0.1.0
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/Gemfile +5 -0
- data/README.markdown +63 -7
- data/Rakefile +11 -0
- data/extend_at.gemspec +3 -1
- data/lib/extend_at/model_manager.rb +136 -0
- data/lib/extend_at/models/all.rb +15 -0
- data/lib/extend_at/models/any_value.rb +5 -0
- data/lib/extend_at/models/binary_value.rb +4 -0
- data/lib/extend_at/models/boolean_value.rb +4 -0
- data/lib/extend_at/models/column.rb +10 -0
- data/lib/extend_at/models/date_value.rb +4 -0
- data/lib/extend_at/models/datetime_value.rb +4 -0
- data/lib/extend_at/models/decimal_value.rb +4 -0
- data/lib/extend_at/models/extend_at.rb +6 -0
- data/lib/extend_at/models/float_value.rb +4 -0
- data/lib/extend_at/models/integer_value.rb +4 -0
- data/lib/extend_at/models/string_value.rb +5 -0
- data/lib/extend_at/models/text_value.rb +5 -0
- data/lib/extend_at/models/time_value.rb +4 -0
- data/lib/extend_at/models/timestamp_value.rb +4 -0
- data/lib/extend_at/version.rb +1 -1
- data/lib/extend_at.rb +138 -20
- data/lib/generators/extend_at/USAGE +8 -0
- data/lib/generators/extend_at/install_generator.rb +22 -0
- data/lib/generators/extend_at/templates/create_extend_at_tables.rb +102 -0
- metadata +45 -4
data/Gemfile
CHANGED
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
|
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 :
|
137
|
-
errors.add :
|
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 :
|
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>:
|
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.
|
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,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
|
+
|
data/lib/extend_at/version.rb
CHANGED
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
|
-
@
|
37
|
+
@model_manager.get_value(key)
|
35
38
|
end
|
36
39
|
|
37
40
|
def []=(key, value)
|
38
|
-
if
|
39
|
-
|
40
|
-
|
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
|
-
@
|
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!
|
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
|
-
|
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
|
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
|
-
|
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,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
|
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-
|
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: &
|
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: *
|
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:
|