iron-enum 1.0.0 → 1.0.1

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.
@@ -1,3 +1,8 @@
1
+ == 1.0.1 / 2013-03-23
2
+
3
+ * Add validation of inclusion for ActiveRecord enum_attr owners
4
+ * Improve docs and spec coverage a bit
5
+
1
6
  == 1.0.0 / 2013-03-23
2
7
 
3
8
  * Initial revision
@@ -12,7 +12,7 @@ Managing constants - status flags, system states, etc - is frustrating when work
12
12
  with Ruby and Rails. The canonical solution is to use class constants. But doing so
13
13
  leaves a lot to be desired. This gem provides a much more Ruby-like way of dealing
14
14
  with magic constants, that provides symbol/key-based lookup, automatic conversion between
15
- keys and values, user-friendly naming, Rails integration, attribute support, and more.
15
+ keys and values, user-friendly naming, attribute support, model scoping and validation, and more.
16
16
 
17
17
  To use:
18
18
 
@@ -48,7 +48,7 @@ To use:
48
48
  => :shipped
49
49
 
50
50
  # Validate values against the set of good values
51
- >> OrderStatus.valid?(10)
51
+ >> OrderStatus.valid_value?(10)
52
52
  => false
53
53
 
54
54
  # Get an array of all valid values
@@ -73,11 +73,21 @@ To use:
73
73
  # Set a value
74
74
  >> @order.status_returned!
75
75
  => 5
76
+
77
+ # Setting an invalid value raises an exception
78
+ # This raises RuntimeError('Unknown key or value [27] in enum OrderStatus')
79
+ >> @order.status = 27
76
80
 
77
81
  # You even get free scoping
78
82
  >> Order.with_status(:shipped)
79
83
  => [...all orders with status == 4...]
80
84
 
85
+ # And model validation, should you somehow set the field to an improper value
86
+ >> @order = Order.new
87
+ >> @order.send(:write_attribute, :status, -2)
88
+ >> @order.valid?
89
+ => false
90
+
81
91
  == REQUIREMENTS
82
92
 
83
93
  None, though you'll need rspec, sqlite3 and active_record gems to test and build the gem
@@ -1 +1 @@
1
- 1.0.0
1
+ 1.0.1
@@ -45,13 +45,13 @@ module Enum
45
45
  module AttrSupport
46
46
 
47
47
  # Call with enum_attr :field => Enum
48
- def enum_attr(name_to_enum_map)
48
+ def enum_attr(field_to_enum_map)
49
49
  # Save off the attr map
50
50
  @enum_attrs ||= {}
51
- @enum_attrs.merge!(name_to_enum_map)
51
+ @enum_attrs.merge!(field_to_enum_map)
52
52
 
53
53
  # Run each newly added enum attribute
54
- name_to_enum_map.each_pair do |attr_name, enum|
54
+ field_to_enum_map.each_pair do |attr_field, enum|
55
55
  # Convert Enum to "Enum"
56
56
  enum_klass = enum.to_s
57
57
 
@@ -59,12 +59,12 @@ module Enum
59
59
  # attr_as_key to get back eg :production or :online instead of 1 or 5
60
60
  # attr_as_name to get back eg "Production" or "Online"
61
61
  class_eval <<-eos, __FILE__, __LINE__ + 1
62
- def #{attr_name}_as_key
63
- #{enum_klass}.key(self.#{attr_name})
62
+ def #{attr_field}_as_key
63
+ #{enum_klass}.key(self.#{attr_field})
64
64
  end
65
65
 
66
- def #{attr_name}_as_name
67
- #{enum_klass}.name(self.#{attr_name})
66
+ def #{attr_field}_as_name
67
+ #{enum_klass}.name(self.#{attr_field})
68
68
  end
69
69
  eos
70
70
 
@@ -75,12 +75,12 @@ module Enum
75
75
 
76
76
  # Build sugar for testing and setting the attribute's enumerated value
77
77
  class_eval <<-eos, __FILE__, __LINE__ + 1
78
- def #{attr_name}_#{key}?
79
- self.#{attr_name} == #{val}
78
+ def #{attr_field}_#{key}?
79
+ self.#{attr_field} == #{val}
80
80
  end
81
81
 
82
- def #{attr_name}_#{key}!
83
- self.#{attr_name} = #{val}
82
+ def #{attr_field}_#{key}!
83
+ self.#{attr_field} = #{val}
84
84
  end
85
85
  eos
86
86
  end
@@ -88,21 +88,28 @@ module Enum
88
88
  if defined?(ActiveRecord) && self < ActiveRecord::Base
89
89
 
90
90
  # Define a finder scope
91
- scope "with_#{attr_name}", lambda {|*vals|
91
+ scope "with_#{attr_field}", lambda {|*vals|
92
92
  vals.flatten!
93
93
  if vals.empty?
94
94
  where("?", false)
95
95
  elsif vals.count == 1
96
- where(attr_name => enum.value(vals.first))
96
+ where(attr_field => enum.value(vals.first))
97
97
  else
98
- where(attr_name => enum.values(vals))
98
+ where(attr_field => enum.values(vals))
99
99
  end
100
100
  }
101
+
102
+ # Define a validation
103
+ validates attr_field, :inclusion => {
104
+ :in => enum.values,
105
+ :message => "%{value} is not a valid #{enum_klass} value",
106
+ :allow_nil => true
107
+ }
101
108
 
102
109
  # Override default setter to allow setting an enum attribute via key
103
110
  class_eval <<-eos, __FILE__, __LINE__ + 1
104
- def #{attr_name}=(val)
105
- write_attribute(:#{attr_name}, #{enum_klass}.value(val))
111
+ def #{attr_field}=(val)
112
+ write_attribute(:#{attr_field}, #{enum_klass}.value(val))
106
113
  end
107
114
  eos
108
115
 
@@ -110,12 +117,12 @@ module Enum
110
117
 
111
118
  # Create getter/setter to allow setting an enum attribute via key
112
119
  class_eval <<-eos, __FILE__, __LINE__ + 1
113
- def #{attr_name}
114
- @#{attr_name}
120
+ def #{attr_field}
121
+ @#{attr_field}
115
122
  end
116
123
 
117
- def #{attr_name}=(val)
118
- @#{attr_name} = #{enum_klass}.value(val)
124
+ def #{attr_field}=(val)
125
+ @#{attr_field} = #{enum_klass}.value(val)
119
126
  end
120
127
  eos
121
128
 
@@ -82,7 +82,7 @@ module Enum
82
82
  def row_for(in_key)
83
83
  key = to_key(in_key)
84
84
  row = enum_list.find {|r| r[KEY_IDX] == key}
85
- raise "No information on key [#{in_key.inspect}] in enum #{self}" unless row
85
+ raise RuntimeError.new("Unknown key or value [#{in_key.inspect}] in enum #{self}") unless row
86
86
  row
87
87
  end
88
88
 
@@ -28,5 +28,9 @@ describe Enum do
28
28
  @obj.pos_as_name.should == 'First'
29
29
  end
30
30
 
31
+ it 'should raise on setting invalid values' do
32
+ expect { @obj.pos = 4000 }.to raise_error
33
+ end
34
+
31
35
  end
32
36
  end
@@ -25,5 +25,15 @@ describe Enum do
25
25
  EnumTest.valid_value?(10).should be_true
26
26
  EnumTest.valid_value?(555).should be_false
27
27
  end
28
+
29
+ it 'should enforce proper keys' do
30
+ expect { EnumTest.enum('not-a-key', 27) }.to raise_error
31
+ expect { EnumTest.enum(27, 100) }.to raise_error
32
+ end
33
+
34
+ it 'should enforce proper values' do
35
+ expect { EnumTest.enum(:some_key, nil) }.to raise_error
36
+ expect { EnumTest.enum(:some_key, '200') }.to raise_error
37
+ end
28
38
 
29
39
  end
@@ -53,6 +53,7 @@ describe Enum do
53
53
 
54
54
  it 'should support multiple values in the automatic scope' do
55
55
  ARTest.delete_all
56
+ ARTest.create!(:enum_field => :one)
56
57
  ARTest.create!(:enum_field => :two)
57
58
  ARTest.create!(:enum_field => 33)
58
59
  ARTest.with_enum_field(2, :thirty_three).count.should == 2
@@ -75,5 +76,20 @@ describe Enum do
75
76
  ARTest.with_enum_field(nil).count.should == 1
76
77
  end
77
78
 
79
+ it 'should fail validation with invalid values' do
80
+ @test.send(:write_attribute, :enum_field, 270)
81
+ @test.should_not be_valid
82
+ end
83
+
84
+ it 'should pass validation with valid values' do
85
+ @test.send(:write_attribute, :enum_field, AREnum::TWO)
86
+ @test.should be_valid
87
+ end
88
+
89
+ it 'should pass validation with a nil value' do
90
+ @test.send(:write_attribute, :enum_field, nil)
91
+ @test.should be_valid
92
+ end
93
+
78
94
  end
79
95
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iron-enum
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: