valuable 0.8.2 → 0.8.4

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