valuable 0.8.2 → 0.8.4

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/lib/valuable.rb CHANGED
@@ -42,13 +42,41 @@ class Valuable
42
42
  # accepts an optional hash that will be used to populate the
43
43
  # predefined attributes for this class.
44
44
  def initialize(atts = nil)
45
- atts.each { |name, value| __send__("#{name}=", value ) } if atts
45
+ self.update_attributes(atts || {})
46
+ end
47
+
48
+ # mass assign attributes. This method will not clear any existing attributes.
49
+ #
50
+ # class Shoe
51
+ # has_value :size
52
+ # has_value :owner
53
+ # has_value :color, :default => 'red'
54
+ # end
55
+ #
56
+ # >> shoe = Shoe.new
57
+ # >> shoe.update_attributes(:size => 16, :owner => 'MJ')
58
+ # >> shoe.attributes
59
+ # => {:size => 16, :owner => 'MJ', :color => 'red'}
60
+ def update_attributes(atts)
61
+ atts.each{|name, value| __send__("#{name}=", value )}
46
62
  end
47
63
 
48
64
  def deep_duplicate_of(value)
49
65
  Marshal.load(Marshal.dump(value))
50
66
  end
51
67
 
68
+ def permissive?
69
+ self.class.permissive_constructor?
70
+ end
71
+
72
+ def method_missing(method_name, *args)
73
+ if method_name.to_s =~ /(\w+)=/
74
+ raise( ArgumentError, "#{self.class.to_s} does not have an attribute or alias '#{$1}'", caller) unless self.permissive?
75
+ else
76
+ super
77
+ end
78
+ end
79
+
52
80
  class << self
53
81
 
54
82
  # Returns an array of the attributes available on this object.
@@ -76,9 +104,7 @@ class Valuable
76
104
  # :klass - light weight type casting. Use :integer, :string or
77
105
  # :boolean. Alternately, supply a class.
78
106
  #
79
- # :alias - creates a second setter with the specified name. This
80
- # allows you to accept information from some other party using their
81
- # vocabulary. Alias does not currently create a getter.
107
+ # :alias - creates an alias for getter and setter with the new name.
82
108
  #
83
109
  # When a :klassified attribute is set to some new value, if the value
84
110
  # is not nil and is not already of that class, the value will be cast
@@ -107,8 +133,10 @@ class Valuable
107
133
  create_question_for(name) if options[:klass] == :boolean
108
134
  create_negative_question_for(name, options[:negative]) if options[:klass] == :boolean && options[:negative]
109
135
 
110
- create_setter_for(name, name, options[:klass])
111
- create_setter_for(name, options[:alias], options[:klass]) if options[:alias]
136
+ create_setter_for(name, options[:klass])
137
+
138
+ alias_method options[:alias], name if options[:alias]
139
+ alias_method "#{options[:alias]}=", "#{name}=" if options[:alias]
112
140
 
113
141
  check_options_validity(name, options)
114
142
  end
@@ -117,38 +145,39 @@ class Valuable
117
145
  # is called both by the constructor. The constructor handles type
118
146
  # casting. Setting values via the attributes hash avoids the method
119
147
  # defined here.
120
- def create_setter_for(attribute, method_name, klass)
148
+ def create_setter_for(attribute, klass)
149
+ setter_method = "#{attribute}="
121
150
 
122
151
  case klass
123
152
  when NilClass
124
153
 
125
- define_method "#{method_name}=" do |value|
154
+ define_method setter_method do |value|
126
155
  attributes[attribute] = value
127
156
  end
128
157
 
129
158
  when :integer
130
159
 
131
- define_method "#{method_name}=" do |value|
160
+ define_method setter_method do |value|
132
161
  value_as_integer = value && value.to_i
133
162
  attributes[attribute] = value_as_integer
134
163
  end
135
164
 
136
165
  when :string
137
166
 
138
- define_method "#{method_name}=" do |value|
167
+ define_method setter_method do |value|
139
168
  value_as_string = value && value.to_s
140
169
  attributes[attribute] = value_as_string
141
170
  end
142
171
 
143
172
  when :boolean
144
173
 
145
- define_method "#{method_name}=" do |value|
174
+ define_method setter_method do |value|
146
175
  attributes[attribute] = value == '0' ? false : !!value
147
176
  end
148
177
 
149
178
  else
150
179
 
151
- define_method "#{method_name}=" do |value|
180
+ define_method setter_method do |value|
152
181
  if value.nil?
153
182
  attributes[attribute] = nil
154
183
  elsif value.is_a? klass
@@ -215,6 +244,37 @@ class Valuable
215
244
  has_value(name, :default => [] )
216
245
  end
217
246
 
247
+ # Instructs the class NOT to complain if any attributes are set
248
+ # that haven't been declared.
249
+ #
250
+ # class Sphere < Valuable
251
+ # has_value :material
252
+ # end
253
+ #
254
+ # >> Sphere.new(:radius => 3, :material => 'water')
255
+ # EXCEPTION! OH NOS!
256
+ #
257
+ # class Box < Valuable
258
+ # acts_as_permissive
259
+ #
260
+ # has_value :material
261
+ # end
262
+ #
263
+ # >> box = Box.new(:material => 'wood', :size => '36 x 40')
264
+ # >> box.attributes
265
+ # => {:material => 'wood'}
266
+ def acts_as_permissive
267
+ self.permissive_constructor=true
268
+ end
269
+
270
+ def permissive_constructor=(value)
271
+ @_permissive_constructor = value
272
+ end
273
+
274
+ def permissive_constructor?
275
+ !!(@_permissive_constructor ||= false)
276
+ end
277
+
218
278
  private
219
279
 
220
280
  def inherited(child)
data/test/alias_test.rb CHANGED
@@ -19,4 +19,9 @@ class AliasTest < Test::Unit::TestCase
19
19
  software = Software.new('EnterpriseNamespace' => 'Enterprisey')
20
20
  assert_equal 'Enterprisey', software.enterprise_namespace
21
21
  end
22
+
23
+ def test_that_aliases_work_for_getters
24
+ software = Software.new(:title => 'ObtrusiveJavascriptComponent')
25
+ assert_equal 'ObtrusiveJavascriptComponent', software.name
26
+ end
22
27
  end
@@ -2,7 +2,6 @@ $: << File.expand_path(File.dirname(__FILE__) + '/../lib')
2
2
 
3
3
  require 'test/unit'
4
4
  require 'valuable.rb'
5
- require 'mocha'
6
5
 
7
6
  class Infrastructure < Valuable
8
7
  end
@@ -20,4 +19,21 @@ class BadAttributesTest < Test::Unit::TestCase
20
19
  Infrastructure.has_value :bar, :klass => Integer
21
20
  end
22
21
  end
22
+
23
+ def test_that_invalid_attributes_raise
24
+ assert_raises ArgumentError do
25
+ model = Class.new(Valuable)
26
+ model.new(:invalid => 'should not be allowed')
27
+ end
28
+ end
29
+
30
+ def test_that_invalid_attributes_can_be_ignored
31
+ assert_nothing_raised do
32
+ model = Class.new(Valuable) do
33
+ acts_as_permissive
34
+ end
35
+ model.new(:invalid => 'should be ignored')
36
+ end
37
+ end
23
38
  end
39
+
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: valuable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ hash: 55
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 8
9
+ - 4
10
+ version: 0.8.4
5
11
  platform: ruby
6
12
  authors:
7
13
  - Johnathon Wright
@@ -9,7 +15,7 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2010-04-06 00:00:00 -05:00
18
+ date: 2010-10-06 00:00:00 -05:00
13
19
  default_executable:
14
20
  dependencies: []
15
21
 
@@ -25,6 +31,11 @@ files:
25
31
  - lib/valuable.rb
26
32
  - README.markdown
27
33
  - rakefile.rb
34
+ - test/bad_attributes_test.rb
35
+ - test/alias_test.rb
36
+ - test/inheritance_test.rb
37
+ - test/deprecated_test.rb
38
+ - test/valuable_test.rb
28
39
  has_rdoc: true
29
40
  homepage: http://valuable.mustmodify.com
30
41
  licenses: []
@@ -35,27 +46,33 @@ rdoc_options: []
35
46
  require_paths:
36
47
  - lib
37
48
  required_ruby_version: !ruby/object:Gem::Requirement
49
+ none: false
38
50
  requirements:
39
51
  - - ">="
40
52
  - !ruby/object:Gem::Version
53
+ hash: 3
54
+ segments:
55
+ - 0
41
56
  version: "0"
42
- version:
43
57
  required_rubygems_version: !ruby/object:Gem::Requirement
58
+ none: false
44
59
  requirements:
45
60
  - - ">="
46
61
  - !ruby/object:Gem::Version
62
+ hash: 3
63
+ segments:
64
+ - 0
47
65
  version: "0"
48
- version:
49
66
  requirements: []
50
67
 
51
68
  rubyforge_project: valuable
52
- rubygems_version: 1.3.5
69
+ rubygems_version: 1.3.7
53
70
  signing_key:
54
71
  specification_version: 3
55
72
  summary: attr_accessor on steroids with defaults, constructor, and light casting.
56
73
  test_files:
57
- - test/inheritance_test.rb
58
- - test/valuable_test.rb
59
74
  - test/bad_attributes_test.rb
60
- - test/deprecated_test.rb
61
75
  - test/alias_test.rb
76
+ - test/inheritance_test.rb
77
+ - test/deprecated_test.rb
78
+ - test/valuable_test.rb