legacy_enum 0.0.1 → 0.1.0

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/README.md ADDED
@@ -0,0 +1,151 @@
1
+ # LegacyEnum
2
+
3
+ Allows your Rails app to interact with C-style integer-backed enumeration db columns using a more Ruby-ish syntax.
4
+
5
+ ```ruby
6
+ class Employee < ActiveRecord::Base
7
+ legacy_enum :payroll_type, lookup: :payroll_type_id do |e|
8
+ e.salaried 1
9
+ e.full_time 2
10
+ e.part_time 3
11
+ end
12
+ end
13
+
14
+ # You can use a symbol syntax for more readable code.
15
+ employee = Employee.new
16
+ employee.payroll_type = :salaried
17
+
18
+ # The database still sees the column as an integer
19
+ p employee.payroll_type_id
20
+ # >> 1
21
+
22
+ # Labels are provided for humanized display of your enum values
23
+ p employee.payroll_type_label
24
+ # >> Salaried
25
+
26
+ # You can still address the column as a integer field (if you have to)
27
+ employee.payroll_type_id = 3
28
+ p employee.payroll_type
29
+ # >> :part_time
30
+ ```
31
+
32
+ ## Requires
33
+
34
+ * Rails >= 3.0
35
+ * Ruby >= 1.9.2
36
+
37
+ ## Why?
38
+
39
+ Lots of legacy apps written in C/C++/C#/Java have integer columns in the database that represent enumerated values in the system.
40
+
41
+ For example, in a legacy system dealing with employees, an employee might be classified with a C-style enumeration like:
42
+
43
+ ```c
44
+ enum PayrollType { Salaried = 1, FullTime, PartTime }
45
+ // stored in a db column named "PayrollTypeID" as its integer value
46
+ ```
47
+
48
+ This could be accessed using legacy_enum like so:
49
+
50
+ ```ruby
51
+ legacy_enum :payroll_type do |e|
52
+ e.salaried 1
53
+ e.full_time 2
54
+ e.part_time 3
55
+ end
56
+ ```
57
+
58
+ ## Usage
59
+
60
+ ```ruby
61
+ legacy_enum [rails_friendly_name], options do |e|
62
+ e.enumerated_name value, [options]
63
+ ...
64
+ end
65
+ ```
66
+
67
+ ## Options
68
+
69
+ #### Lookups
70
+
71
+ Conventionally, legacy_enum assumes that the backing int column is named the same as your field name, capitalized and postfixed with "ID". If that isn't the case, use the "lookup" option.
72
+
73
+ ```ruby
74
+ legacy_enum :payroll_type, lookup: :unconventional_id_column_name do |e|
75
+ ...
76
+ end
77
+ ```
78
+
79
+ #### Values
80
+
81
+ Legacy_enum requires that a backing value be provided for each enumerated name. A value can be an integer or a string.
82
+
83
+ ```ruby
84
+ legacy_enum :int_values do |e|
85
+ e.some_value 32
86
+ e.another_value 64
87
+ end
88
+
89
+ legacy_enum :string_values do |e|
90
+ e.a_string_value_is_ok 'zip_zop_zoobity_bop'
91
+ e.another_string 'here_i_go_down_the_slope'
92
+ end
93
+ ```
94
+
95
+ #### Labels
96
+
97
+ Labels are automatically created and conventionally have the name [legacy_enum_field]_label. For instance, this definition would have a label named 'foo_label'
98
+
99
+ ```ruby
100
+ legacy_enum :foo do |e|
101
+ e.some_value 1
102
+ end
103
+ ```
104
+
105
+ Each enumerated name, by default, has a label that is just the ActiveSupport#Titleized version of the enum name. This can be overridden using the 'label' option for each value.
106
+
107
+ ```ruby
108
+ legacy_enum :foo do |e|
109
+ e.crazy_label 1, label: 'Roflcopter'
110
+ end
111
+
112
+ foo = :crazy_label
113
+ p foo_label
114
+ # >> 'Roflcopter'
115
+ ```
116
+
117
+ #### Scopes
118
+
119
+ ActiveRecord scopes can be created for your enumerated field, although by default they are not. The 'scope' option supports two values, :many and :one. 'Many' creates a scope with the enumeration name that accepts symbol values for the scope.
120
+
121
+ ```ruby
122
+ class Employee < ActiveRecord::Base
123
+ legacy_enum :payroll_type, lookup: :payroll_type_id, scope: :many do |e|
124
+ e.salaried 1
125
+ e.full_time 2
126
+ e.part_time 3
127
+ end
128
+ end
129
+
130
+ # The following scopes are created
131
+ Employee.payroll_type(:salaried)
132
+ # 'SELECT * FROM employees WHERE payroll_type_id = 1'
133
+ Employee.salaried
134
+ # 'SELECT * FROM employees WHERE payroll_type_id = 1'
135
+ Employee.full_time
136
+ # 'SELECT * FROM employees WHERE payroll_type_id = 2'
137
+ Employee.part_time
138
+ # 'SELECT * FROM employees WHERE payroll_type_id = 3'
139
+ ```
140
+
141
+ ## Who?
142
+
143
+ legacy_enum was written by [Sean Scally](http://github.com/anydiem) for [AutoRevo](http://www.autorevo.com) with code contributed by [Matt Shannon](http://github.com/dmshann0n).
144
+
145
+ legacy_enum was inspired by jeffp's [enumerated_attribute](http://github.com/jeffp/enumerated_attribute).
146
+
147
+ ## License
148
+
149
+ Released under the MIT license:
150
+
151
+ * http://www.opensource.org/licenses/MIT
@@ -1,84 +1,79 @@
1
1
  module LegacyEnum
2
2
  module ClassMethods
3
3
  def legacy_enum(name, *options, &block)
4
- values_name = "@@#{name}_values".downcase
5
- options = options.extract_options!
6
- id_attr_name = options[:lookup].try(:to_s) || "#{name.to_s.capitalize}ID"
4
+ extracted_options = options.extract_options!
5
+ id_attr_name = extracted_options[:lookup].try(:to_s) || "#{name.to_s.capitalize}ID"
7
6
 
8
7
  config = MethodDefinitionDSL.new
9
8
  config.instance_eval(&block)
10
9
 
11
10
  cattr_accessor :enum_config unless defined? self.enum_config
12
11
  self.enum_config ||= {}
13
- self.enum_config[name] = config.enum_def
14
12
 
15
- #TODO make more lightweight by conditionally adding these methods on first use via method_missing
13
+ self.enum_config[name] = { values: config.enum_def, lookup: id_attr_name }
14
+
16
15
  class_eval do
17
- if options[:scope]
18
- scope name.to_sym, lambda { |enum_val|
19
- { :conditions => { id_attr_name.to_sym => enums[name.to_sym][enum_val] } }
20
- }
21
- self.enums[name].keys.each do |value|
22
- if options[:scope] == :one
23
- (class << self; self; end).instance_eval do
24
- define_method value.to_sym, lambda {
25
- send(name.to_sym, value.to_sym).first
26
- }
27
- end
28
- else
29
- (class << self; self; end).instance_eval do
30
- define_method value.to_sym, lambda {
31
- send(name.to_sym, value.to_sym)
32
- }
33
- end
34
- end
35
- end
16
+
17
+ define_method name do
18
+ enum_config[name][:values].valued(legacy_value(name))[:name]
36
19
  end
37
20
 
38
- find_enum_entry = Proc.new do |_self, name, sym|
39
- enum_entry = _self.enum_config[name].find do |hash|
40
- attr_value = _self.send(id_attr_name.to_sym)
41
- attr_value.to_s.upcase == hash[:value].to_s.upcase
42
- end
21
+ define_method "#{name}=" do |value|
22
+ set_value = enum_config[name][:values].named(value)[:value]
23
+ set_legacy_value name, set_value
24
+ end
43
25
 
44
- enum_entry[sym] unless enum_entry.blank?
26
+ define_method "#{name}_label" do
27
+ enum_config[name][:values].valued(legacy_value(name))[:label]
45
28
  end
46
29
 
47
- define_method name do
48
- find_enum_entry.call(self, name, :name)
30
+ def legacy_value(name)
31
+ send enum_config[name][:lookup].to_sym
49
32
  end
50
33
 
51
- define_method "#{name}=" do |value|
52
- self.send("#{id_attr_name}=".to_sym, nil) if value.blank?
53
- enum_entry = self.enum_config[name].find { |hash| hash[:name] == (value.blank? ? value : value.to_sym) }
54
- unless enum_entry.blank?
55
- self.send("#{id_attr_name}=".to_sym, enum_entry[:value])
56
- end
34
+ def set_legacy_value(name, value)
35
+ send "#{enum_config[name][:lookup]}=".to_sym, value
57
36
  end
58
37
 
59
- define_method "#{name}_label" do
60
- find_enum_entry.call(self, name, :label)
38
+ return unless extracted_options[:scope]
39
+
40
+ scope name.to_sym,
41
+ lambda { |enum_value| where(id_attr_name => enum_config[name][:values].named(enum_value)[:value] ) }
42
+
43
+ enum_config[name][:values].each do |config|
44
+ singleton_class.instance_eval do
45
+ if extracted_options[:scope] == :one
46
+ define_method config[:name].to_sym, lambda { send(name, config[:name]).first }
47
+ else
48
+ define_method config[:name].to_sym, lambda { send(name, config[:name]) }
49
+ end
50
+ end
61
51
  end
52
+
62
53
  end
54
+
63
55
  end
64
56
 
57
+ # Returns all enumerations for the class by enum_name and then name => value
65
58
  def enums
66
59
  inject_block(:name, :value)
67
60
  end
68
61
 
62
+ # Returns all enumerations for the class by enum_name and then name => label
69
63
  def labels
70
64
  inject_block(:name, :label)
71
65
  end
72
66
 
67
+ # Returns all enumerations for the class by enum_name and then value => name
73
68
  def enum_ids
74
69
  inject_block(:value, :name)
75
70
  end
76
71
 
77
72
  private
78
- #this name sux, refactor it
73
+ # Restructures the enum_config around a key/value pair
79
74
  def inject_block(key, value)
80
75
  self.enum_config.inject({}) do |acc, (name,config)|
81
- acc.merge( { name => config.inject({}) do |inner_acc, enum_item|
76
+ acc.merge( { name => config[:values].inject({}) do |inner_acc, enum_item|
82
77
  inner_acc.merge( { enum_item[key] => enum_item[value] } )
83
78
  end })
84
79
  end
@@ -0,0 +1,21 @@
1
+ module LegacyEnum
2
+ module ConfigurationSearch
3
+ def named(name)
4
+ find { |config| config[:name] == name } || null_definition
5
+ end
6
+
7
+ def valued(value)
8
+ search_value = value.to_s.upcase
9
+ find { |config| config[:value].to_s.upcase === search_value } || null_definition
10
+ end
11
+
12
+ def labelled(label)
13
+ find { |config| config[:label] == label } || null_definition
14
+ end
15
+
16
+ private
17
+ def null_definition
18
+ { name: nil, value: nil, label: nil }
19
+ end
20
+ end
21
+ end
@@ -4,6 +4,7 @@ module LegacyEnum
4
4
 
5
5
  def method_missing(symbol, *args)
6
6
  @enum_def ||= []
7
+ @enum_def.singleton_class.send :include, ConfigurationSearch
7
8
 
8
9
  options = args.extract_options!
9
10
 
@@ -1,3 +1,3 @@
1
1
  module LegacyEnum
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/legacy_enum.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'active_record'
2
2
 
3
+ require 'legacy_enum/configuration_search'
3
4
  require 'legacy_enum/method_definition_dsl'
4
5
  require 'legacy_enum/class_methods'
5
6
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: legacy_enum
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-08 00:00:00.000000000 Z
12
+ date: 2012-02-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
- requirement: &70179477187020 !ruby/object:Gem::Requirement
16
+ requirement: &70249318379200 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>'
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 3.0.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70179477187020
24
+ version_requirements: *70249318379200
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: sqlite3
27
- requirement: &70179477186600 !ruby/object:Gem::Requirement
27
+ requirement: &70249318378160 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70179477186600
35
+ version_requirements: *70249318378160
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &70179477186140 !ruby/object:Gem::Requirement
38
+ requirement: &70249318376680 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70179477186140
46
+ version_requirements: *70249318376680
47
47
  description: Allows you to address enumerated integer columns as more sane and readable
48
48
  symbols
49
49
  email:
@@ -53,13 +53,14 @@ extensions: []
53
53
  extra_rdoc_files: []
54
54
  files:
55
55
  - lib/legacy_enum/class_methods.rb
56
+ - lib/legacy_enum/configuration_search.rb
56
57
  - lib/legacy_enum/method_definition_dsl.rb
57
58
  - lib/legacy_enum/version.rb
58
59
  - lib/legacy_enum.rb
59
60
  - lib/tasks/legacy_enum_tasks.rake
60
61
  - MIT-LICENSE
61
62
  - Rakefile
62
- - README.rdoc
63
+ - README.md
63
64
  homepage: http://github.com/anydiem/legacy_enum
64
65
  licenses: []
65
66
  post_install_message:
data/README.rdoc DELETED
@@ -1,5 +0,0 @@
1
- = LegacyEnum
2
-
3
- = TODO
4
- - Refactor test cases
5
- - More test coverage