has_eav 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.1
1
+ 1.1.0
data/has_eav.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{has_eav}
8
- s.version = "1.0.1"
8
+ s.version = "1.1.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Hartog C. de Mik"]
12
- s.date = %q{2010-12-10}
12
+ s.date = %q{2011-03-21}
13
13
  s.description = %q{Put EAV behaviour on your ActiveRecord models}
14
14
  s.email = %q{hcdm@matchvertise.com}
15
15
  s.extra_rdoc_files = [
data/lib/has_eav.rb CHANGED
@@ -1,10 +1,10 @@
1
1
  module ActiveRecord
2
2
  module ActsAs
3
3
  module HasEav
4
- def self.included(base)
5
- base.extend ActiveRecord::ActsAs::HasEav::ClassMethods
4
+ def self.included(base)
5
+ base.extend ActiveRecord::ActsAs::HasEav::ClassMethods
6
6
  end
7
-
7
+
8
8
  module ClassMethods
9
9
  # Specify that the ActiveModel is an EAV model
10
10
  #
@@ -36,59 +36,59 @@ module ActiveRecord
36
36
  "Eav Class cannot be nil. Specify a class using " +
37
37
  "has_eav :through => :class"
38
38
  ) if klass.blank?
39
-
39
+
40
40
  class_eval do
41
41
  after_save :save_eav_attributes
42
42
  end
43
-
43
+
44
44
  @eav_class = klass.to_s.camelize.constantize
45
45
  @eav_attributes = {}
46
-
46
+
47
47
  yield if block_given?
48
-
48
+
49
49
  send :include, ActiveRecord::ActsAs::HasEav::InstanceMethods
50
50
  end
51
-
51
+
52
52
  # Add an other attribute to the class list
53
53
  def eav_attribute name, type = String
54
54
  name = name.to_s if !name.is_a? String
55
-
55
+
56
56
  self.class_eav_attributes[name] = type
57
57
  end
58
-
58
+
59
59
  # class accessor - when the superclass != AR::Base asume we are in STI
60
60
  # mode
61
61
  def class_eav_attributes # :nodoc:
62
62
  superclass != ActiveRecord::Base ?
63
63
  superclass.class_eav_attributes :
64
- @eav_attributes
64
+ @eav_attributes
65
65
  end
66
-
66
+
67
67
  # class accessor - when the superclass != AR::Base asume we are in STI
68
68
  # mode
69
69
  def eav_class # :nodoc:
70
70
  superclass != ActiveRecord::Base ? superclass.eav_class : @eav_class
71
- end
71
+ end
72
72
  end # /ClassMethods
73
-
73
+
74
74
  module InstanceMethods
75
75
  # get to the eav class
76
76
  def eav_class
77
77
  self.class.eav_class
78
78
  end
79
-
79
+
80
80
  # get the class eav attributes
81
81
  def class_eav_attributes
82
82
  self.class.class_eav_attributes
83
83
  end
84
-
84
+
85
85
  # Override this to get some usable attributes
86
- #
86
+ #
87
87
  # Cowardly refusing to adhere to all
88
88
  def instance_eav_attributes
89
89
  []
90
- end
91
-
90
+ end
91
+
92
92
  # override method missing, but only kick in when super fails with a
93
93
  # NoMethodError
94
94
  #
@@ -97,62 +97,62 @@ module ActiveRecord
97
97
  rescue NoMethodError => e
98
98
  method_name = method_symbol.to_s
99
99
  attribute_name = method_name.gsub(/[\?=]$/, '')
100
-
100
+
101
101
  raise e unless eav_attributes_list.include? attribute_name
102
-
102
+
103
103
  attribute = self.eav_attributes.select { |a|
104
104
  a.name == attribute_name
105
105
  }.first
106
-
106
+
107
107
  if method_name =~ /\=$/
108
108
  value = args[0]
109
-
109
+
110
110
  if attribute
111
111
  if value
112
112
  return attribute.send(:write_attribute, "value", value)
113
-
113
+
114
114
  elsif value.nil?
115
115
  return attribute.destroy
116
-
116
+
117
117
  end
118
-
118
+
119
119
  else
120
120
  @eav_attributes << eav_class.new(
121
121
  :name => attribute_name,
122
122
  :value => "#{value}"
123
123
  )
124
-
124
+
125
125
  return cast_eav_value(value, attribute_name)
126
-
126
+
127
127
  end
128
128
  elsif method_name =~ /\?$/
129
129
  return ( attribute and attribute.value == true ) ? true : false
130
-
130
+
131
131
  else
132
- return attribute ?
132
+ return attribute ?
133
133
  cast_eav_value(attribute.value, attribute_name) :
134
134
  nil
135
-
135
+
136
136
  end
137
-
137
+
138
138
  raise e
139
- end
140
-
139
+ end
140
+
141
141
  # override respond_to?
142
142
  def respond_to? method_symbol, is_private=false
143
143
  if super == false
144
144
  method_name = method_symbol.to_s.gsub(/[\?=]$/, '')
145
145
  return true if eav_attributes_list.include? method_name
146
-
146
+
147
147
  false
148
148
  else
149
149
  true
150
150
  end
151
- end
152
-
151
+ end
152
+
153
153
  # get all the eav attribute instances available for this model instance
154
154
  #
155
- # eg: if you model says 'has_eav :through => :post_attribute' these are
155
+ # eg: if you model says 'has_eav :through => :post_attribute' these are
156
156
  # all PostAttribute's
157
157
  #
158
158
  def eav_attributes
@@ -160,60 +160,75 @@ module ActiveRecord
160
160
  :conditions => { self_key => self.id }
161
161
  )
162
162
  end
163
-
163
+
164
164
  # save the list of eav_attribute back to the database
165
165
  def save_eav_attributes # :nodoc:
166
166
  eav_attributes.select { |a| a.changed? }.each do |a|
167
167
  if a.new_record?
168
168
  a.send( :write_attribute, self_key, self.id )
169
169
  end
170
-
170
+
171
171
  a.save!
172
172
  end
173
173
  end
174
-
175
- # override changed - if any of the eav_attributes has changed, the
174
+
175
+ # override changed - if any of the eav_attributes has changed, the
176
176
  # object has changed.
177
177
  #
178
178
  def changed?
179
- eav_attributes.each do |attribute|
179
+ eav_attributes.each do |attribute|
180
180
  return true if ( attribute.changed? || attribute.new_record? )
181
181
  end
182
-
182
+
183
183
  super
184
184
  end
185
-
185
+
186
186
  # get a complete list of eav_attributes (class + instance)
187
187
  def eav_attributes_list # :nodoc:
188
188
  (
189
189
  self.instance_eav_attributes + self.class_eav_attributes.keys
190
190
  ).collect { |attribute| attribute.to_s }.uniq
191
191
  end
192
-
192
+
193
193
  # get the key to my <3
194
194
  def self_key # :nodoc:
195
195
  klass = self.class
196
196
  if klass.superclass != ActiveRecord::Base
197
197
  klass = klass.superclass
198
198
  end
199
-
199
+
200
200
  "#{klass.name.underscore}_id".to_sym
201
201
  end
202
-
202
+
203
203
  # cast an eav value to it's desired class
204
204
  def cast_eav_value value, attribute # :nodoc:
205
205
  attributes = self.class_eav_attributes.stringify_keys
206
206
  return value unless attributes.keys.include?(attribute)
207
-
208
- return (
209
- eval("#{attributes[attribute]} '#{value}'") ||
210
- eval("#{attributes[attribute]}.new('#{value}')") ||
211
- value
212
- )
207
+
208
+
209
+ begin
210
+ # for core types [eg: String 'foo']
211
+ eval("#{attributes[attribute]} '#{value}'")
212
+
213
+ rescue
214
+ begin
215
+ # for BigDecimal [eg: BigDecimal.new("123.45")]
216
+ eval("#{attributes[attribute]}.new('#{value}')")
217
+
218
+ rescue
219
+ begin
220
+ # for date/time classes [eg: Date.parse("2011-03-20")]
221
+ eval("#{attributes[attribute]}.parse('#{value}')")
222
+ rescue
223
+ value
224
+ end
225
+
226
+ end
227
+ end
213
228
  end
214
-
229
+
215
230
  protected :save_eav_attributes, :self_key, :cast_eav_value
216
-
231
+
217
232
  end # /InstanceMethods
218
233
  end # /HasEav
219
234
  end # /ActsAs
@@ -1,6 +1,8 @@
1
1
  class Post < ActiveRecord::Base
2
2
  has_eav :through => :post_attribute do
3
3
  eav_attribute :author_name
4
- eav_attribute :author_email
4
+ eav_attribute :author_email
5
+ eav_attribute :published_on, Date
6
+ eav_attribute :last_update, Time
5
7
  end
6
8
  end
data/test/test_has_eav.rb CHANGED
@@ -1,54 +1,57 @@
1
1
  require 'helper'
2
2
 
3
3
  class TestHasEav < Test::Unit::TestCase
4
+ #
5
+ # A model under EAV ...
6
+ #
4
7
  should "be able to create new records" do
5
8
  before = Post.count
6
9
  Post.create( :title => "Hello world", :contents => "Lipsum" )
7
10
  assert_equal before + 1, Post.count, "count has incremented by 1"
8
11
  end
9
-
12
+
10
13
  should "be able to write to an eav attribute" do
11
14
  p = Post.last
12
15
  assert_equal p.author_name = "hartog", "hartog", "eav attribute set"
13
16
  end
14
-
17
+
15
18
  should "propperly respond_to? eav_attributes" do
16
19
  p = Post.new
17
20
  assert p.respond_to?(:author_name), "responds to author name"
18
21
  assert !p.respond_to?(:author_gender), "does not respond to gender"
19
22
  end
20
-
23
+
21
24
  should "propperly implement changed?" do
22
25
  p = Post.last
23
26
  assert !p.changed?, "is not changed"
24
-
27
+
25
28
  p = Post.last
26
29
  p.author_name = rand 100
27
-
30
+
28
31
  assert p.changed?, "is changed only by eav attribute"
29
-
32
+
30
33
  p = Post.last
31
34
  p.title = "Bye World"
32
35
  assert p.changed?, "is changed on real attribute"
33
36
  end
34
-
35
- should "save PostAttribute's" do
37
+
38
+ should "save PostAttribute's on Post.create" do
36
39
  before = PostAttribute.count
37
40
  p = Post.create( :title => "Hello World", :contents => "Lipsum" )
38
41
  p.author_name = "hartog"
39
42
  p.save!
40
-
43
+
41
44
  assert_equal before + 1, PostAttribute.count, "count has incremented by 1"
42
45
  end
43
-
46
+
44
47
  should "save ProductAttribute's on Product.create" do
45
48
  before = ProductAttribute.count
46
49
  p = Product.create(
47
50
  :name => "test",
48
51
  :description => "spiffy. new.",
49
52
  :price => 12.95
50
- )
51
-
53
+ )
54
+
52
55
  assert_equal before + 1, ProductAttribute.count, "count has incremented by 1"
53
56
  end
54
57
 
@@ -56,41 +59,57 @@ class TestHasEav < Test::Unit::TestCase
56
59
  p = Product.create( :name => "test", :description => "test" )
57
60
  p.price = 12.95
58
61
  p.save!
59
-
60
- p = Product.last
62
+
63
+ p = Product.last
61
64
  assert p.price.is_a?(Float), "casted"
62
65
  assert p.price == 12.95, "same"
63
66
  end
64
-
67
+
65
68
  should "cast values with new" do
66
69
  test_val ="13.24458724857"
67
70
  p = Product.create(
68
71
  :name => "test", :description => "test", :cost_price => test_val
69
72
  )
70
-
71
- p = Product.last
73
+
74
+ p = Product.last
72
75
  assert p.cost_price.is_a?(BigDecimal), "casted"
73
76
  assert p.cost_price == BigDecimal.new(test_val), "same"
74
77
  end
75
-
78
+
76
79
  should "not find by eav attribute" do
77
80
  p = Post.create(
78
81
  :title => "title", :contents => "lorem ipsum", :author_name => "hartog"
79
82
  )
80
-
83
+
81
84
  post = nil
82
85
  begin
83
86
  post = Post.find_by_author_name "hartog"
84
87
  rescue
85
88
  post = "failed"
86
89
  end
87
-
90
+
88
91
  assert_equal "failed", post, "has failed"
89
92
  end
90
-
93
+
91
94
  should "work with STI" do
92
95
  p = SpecialPost.create(
93
96
  :title => "title", :contents => "lorem ipsum", :author_name => "hartog"
94
97
  )
95
98
  end
99
+
100
+ should "be able to handle Date casting" do
101
+ p = Post.last
102
+ p.published_on = Date.yesterday
103
+
104
+ assert_equal Date.yesterday, p.published_on, "Date comparisson"
105
+ end
106
+
107
+ should "be able to handle Time casting" do
108
+ t = Time.now
109
+
110
+ p = Post.last
111
+ p.last_update = t
112
+
113
+ assert_equal t.to_i, p.last_update.to_i, "Time comparisson"
114
+ end
96
115
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: has_eav
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 19
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 0
9
8
  - 1
10
- version: 1.0.1
9
+ - 0
10
+ version: 1.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Hartog C. de Mik
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-12-10 00:00:00 +01:00
18
+ date: 2011-03-21 00:00:00 +01:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency