iron-enum 1.0.0 → 1.0.1

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