enumerations 1.3.2 → 2.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 6c202450cd19bc9f524f6ef5756c44bd304a4ef6047d274abda8d165601b6e64
4
- data.tar.gz: 61977fd20143ade7cb63242cc0b6098a981861783b412b62fa6b36e28b195f35
2
+ SHA1:
3
+ metadata.gz: a75cec2684b73e9e83a7b60ddd48b95ac01fd991
4
+ data.tar.gz: 822d8484b921612c31deadd8491994ad1e22a66d
5
5
  SHA512:
6
- metadata.gz: 60cb0a9f041e566e090e7b26b5a099f912e6a63a94a652a165b1e83f1d71fd5b7d280c25ebe13e1bca12d16c4dd0407f8db736ad7893ec2ed491a21ef199ffbc
7
- data.tar.gz: 04f4aff2e90b826b5e47022083c919d28f561b9370963b9c37251c83eb1101c68b1500624c3ef0e4e039c88465da46a1afe707cd5cda15778dfb47a4bae16ed4
6
+ metadata.gz: 3df5039cf8d021b312058982c26edee6d8e24c56bd05a4f9cba6db2f55adef3f311d3181a544e774cd3607750d0c813e4935fcbf3079608eec3a7a142a546d4d
7
+ data.tar.gz: 04c31625eecf7f4276bf11d673aa66d2290ca086d49d728502cde004166a32c7a2ff051367356299feeee8399afc0b486551b00694b51fe47b69d1e72aaf05d1
data/Readme.md CHANGED
@@ -1,9 +1,12 @@
1
1
  Enumerations
2
2
  ============
3
3
 
4
- Rails plugin for enumerations in ActiveRecord models.
4
+ [![Gem Version](https://badge.fury.io/rb/enumerations.svg)](https://badge.fury.io/rb/enumerations)
5
+ [![Code Climate](https://codeclimate.com/github/infinum/enumerations/badges/gpa.svg)](https://codeclimate.com/github/infinum/enumerations)
6
+ [![Build Status](https://semaphoreci.com/api/v1/infinum/enumerations/branches/master/shields_badge.svg)](https://semaphoreci.com/infinum/enumerations)
7
+ [![Test Coverage](https://codeclimate.com/github/infinum/enumerations/badges/coverage.svg)](https://codeclimate.com/github/infinum/enumerations/coverage)
5
8
 
6
- [![Build Status](https://travis-ci.org/infinum/enumerations.svg?branch=master)](https://travis-ci.org/infinum/enumerations)
9
+ Rails plugin for enumerations in ActiveRecord models.
7
10
 
8
11
  Installation
9
12
  ============
@@ -17,10 +20,12 @@ gem 'enumerations'
17
20
  Usage
18
21
  =====
19
22
 
23
+ ## Defining enumerations
24
+
20
25
  Create a model for your enumerations:
21
26
 
22
27
  ```ruby
23
- class Status < Enumeration::Base
28
+ class Status < Enumerations::Base
24
29
  values draft: { id: 1, name: 'Draft' },
25
30
  review_pending: { id: 2, name: 'Review pending' },
26
31
  published: { id: 3, name: 'Published' }
@@ -30,7 +35,7 @@ end
30
35
  Or you can use `value` method for defining your enumerations:
31
36
 
32
37
  ```ruby
33
- class Status < Enumeration::Base
38
+ class Status < Enumerations::Base
34
39
  value :draft, id: 1, name: 'Draft'
35
40
  value :review_pending, id: 2, name: 'Review pending'
36
41
  value :published, id: 3, name: 'Published'
@@ -46,16 +51,21 @@ class Post < ActiveRecord::Base
46
51
  end
47
52
  ```
48
53
 
49
- You can pass attributes to specify which enumeratior and which column to use:
54
+ You can pass attributes to specify which enumeration and which column to use:
50
55
 
51
56
  ```ruby
52
57
  class Post < ActiveRecord::Base
53
58
  enumeration :status,
54
- foreign_key: :post_status_id, # specifies which column to use
55
- class_name: Post::Status # specifies the class of the enumerator
59
+ foreign_key: :post_status_id, # specifies which column to use
60
+ class_name: Post::Status # specifies the class of the enumerator
56
61
  validates :post_status_id, presence: true
57
62
  end
58
63
  ```
64
+ Attribute `foreign_key` you can pass as a `String` or a `Symbol`. Attribute `class_name` can be set as a `String`, a `Symbol` or a `String`.
65
+
66
+
67
+
68
+ ## Setting enumeration value to objects
59
69
 
60
70
  Set enumerations, find enumerations by `symbol`:
61
71
 
@@ -71,20 +81,56 @@ Or you can set enumerations on this way:
71
81
  @post.status = Status.draft
72
82
  ```
73
83
 
84
+ Also, you can set enumeration value like this:
85
+
86
+ ```ruby
87
+ @post.status_draft!
88
+ ```
89
+
90
+ > When you include enumerations into your model, you'll get methods for setting each enumeration value. Each method name is consists from enumeration name and enumeration value name with **!** at the end. Examples:
91
+
92
+ ```ruby
93
+ class Post < ActiveRecord::Base
94
+ enumeration :status
95
+ end
96
+
97
+ @post.status_draft!
98
+ ```
99
+
100
+ ```ruby
101
+ class User < ActiveRecord::Base
102
+ enumeration :role
103
+ end
104
+
105
+ @user.role_admin!
106
+ ```
107
+
108
+ ```ruby
109
+ class User < ActiveRecord::Base
110
+ enumeration :type, class_name: Role
111
+ end
112
+
113
+ @user.type_editor!
114
+ ```
115
+
116
+
117
+
118
+ ## Finder methods
119
+
74
120
  Find enumerations by `id`:
75
121
 
76
122
  ```ruby
77
- @post.status = Status.find(2) # => Review pending
123
+ @post.status = Status.find(2) # => Review pending
78
124
  @post.save
79
125
  ```
80
126
 
81
127
  Compare enumerations:
82
128
 
83
129
  ```ruby
84
- @post.status == :published # => true
85
- @post.status == 3 # => true
86
- @post.status == Status.find(:published) # => true
87
- @post.status.published? # => true
130
+ @post.status == :published # => true
131
+ @post.status == 3 # => true
132
+ @post.status == Status.find(:published) # => true
133
+ @post.status.published? # => true
88
134
  ```
89
135
 
90
136
  Get all enumerations:
@@ -93,6 +139,43 @@ Get all enumerations:
93
139
  Status.all
94
140
  ```
95
141
 
142
+
143
+
144
+ ## Scopes on model
145
+
146
+ With enumerations, you'll get scope for each enumeration value in the
147
+ following format:
148
+
149
+ ```ruby
150
+ with_#{enumeration_name}_#{enumeration_value_name}
151
+ ```
152
+
153
+ Examples:
154
+
155
+ ```ruby
156
+ class Post < ActiveRecord::Base
157
+ enumeration :status
158
+ end
159
+
160
+ Post.with_status_draft # => <#ActiveRecord::Relation []>
161
+ Post.with_status_review_pending # => <#ActiveRecord::Relation []>
162
+ ```
163
+
164
+ ```ruby
165
+ class Post < ActiveRecord::Base
166
+ enumeration :my_status, class_name: Status
167
+ end
168
+
169
+ Post.with_my_status_draft # => <#ActiveRecord::Relation []>
170
+ Post.with_my_status_review_pending # => <#ActiveRecord::Relation []>
171
+ ```
172
+
173
+ Each scope returns all records with specified enumeration value.
174
+
175
+
176
+
177
+ ## Forms usage
178
+
96
179
  Use in forms:
97
180
 
98
181
  ```ruby
@@ -108,7 +191,7 @@ Advance Usage
108
191
  Except `id` and `name` you can specify other attributes to your enumerations:
109
192
 
110
193
  ```ruby
111
- class Status < Enumeration::Base
194
+ class Status < Enumerations::Base
112
195
  value :draft, id: 1, name: 'Draft'
113
196
  value :review_pending, id: 2, name: 'Review pending', description: 'Some description...'
114
197
  value :published, id: 3, name: 'Published'
@@ -118,8 +201,8 @@ end
118
201
  Every enumeration has `id`, `name` and `description` methods. If you call method that is not in attribute list for enumeration, it will return `nil`.
119
202
 
120
203
  ```ruby
121
- Status.review_pending.description # => 'Some description...'
122
- Status.draft.description # => nil
204
+ Status.review_pending.description # => 'Some description...'
205
+ Status.draft.description # => nil
123
206
  ```
124
207
 
125
208
  Author
data/enumerations.gemspec CHANGED
@@ -2,9 +2,9 @@ require File.expand_path('../lib/enumerations/version', __FILE__)
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'enumerations'
5
- s.version = Enumeration::VERSION
6
- s.date = '2010-08-20'
7
- s.summary = "Enumerations for ActiveRecord!"
5
+ s.version = Enumerations::VERSION
6
+ s.date = '2016-08-15'
7
+ s.summary = 'Enumerations for ActiveRecord!'
8
8
  s.description = 'Extends ActiveRecord with enumeration capabilites.'
9
9
  s.authors = ['Tomislav Car', 'Nikica Jokic', 'Nikola Santic']
10
10
  s.email = ['tomislav@infinum.hr', 'nikica.jokic@infinum.hr', 'nikola.santic@infinum.hr']
@@ -13,6 +13,9 @@ Gem::Specification.new do |s|
13
13
  s.add_dependency 'activerecord'
14
14
  s.add_dependency 'activesupport'
15
15
  s.add_development_dependency 'pry-byebug'
16
+ s.add_development_dependency 'rake'
17
+ s.add_development_dependency 'codeclimate-test-reporter'
18
+ s.add_development_dependency 'sqlite3'
16
19
 
17
20
  s.files = `git ls-files`.split("\n")
18
21
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
data/lib/enumerations.rb CHANGED
@@ -7,8 +7,7 @@ require 'enumerations/version'
7
7
  require 'enumerations/base'
8
8
  require 'enumerations/reflection'
9
9
 
10
- # TODO: rename to Enumeration(s) in a major version change
11
- module Enumeration
10
+ module Enumerations
12
11
  extend ActiveSupport::Concern
13
12
 
14
13
  included do
@@ -27,17 +26,15 @@ module Enumeration
27
26
  # end
28
27
  #
29
28
  # user.role_id = 1
30
- # user.role => #<Enumeration::Value:0x007fff45d7ec30 @base=Role, @symbol=:admin...>
29
+ # user.role => #<Enumerations::Value: @base=Role, @symbol=:admin...>
31
30
  #
32
31
  # user.role = Role.staff
33
32
  # user.role_id => 2
34
33
  #
35
- # TODO: add documentation for foreign_key and class_name
36
34
  def enumeration(name, options = {})
37
- options[:foreign_key] ||= "#{name}_id".to_sym
38
- options[:class_name] ||= name.to_s.camelize
35
+ reflection = Reflection.new(name, options)
39
36
 
40
- add_enumeration(name, options)
37
+ add_enumeration(reflection)
41
38
  end
42
39
 
43
40
  # Output all the enumerations that this model has defined
@@ -47,8 +44,9 @@ module Enumeration
47
44
  # Example:
48
45
  #
49
46
  # User.reflect_on_all_enumerations => # [
50
- # #<Enumeration::Reflection:0x007fe894724320 @name=:role...>,
51
- # #<Enumeration::Reflection:0x007fe89471d020 @name=:status...>]
47
+ # #<Enumerations::Reflection: @name=:role...>,
48
+ # #<Enumerations::Reflection: @name=:status...>
49
+ # ]
52
50
  #
53
51
  def reflect_on_all_enumerations
54
52
  _enumerations
@@ -56,41 +54,75 @@ module Enumeration
56
54
 
57
55
  private
58
56
 
59
- def add_enumeration(name, options)
60
- # Getter for belongs_to
61
- #
62
- # Example:
63
- #
64
- # user.role_id = 1
65
- # user.role => #<Enumeration::Value:0x007fff45d7ec30 @base=Role, @symbol=:admin...>
66
- #
67
- define_method name do
68
- enumerator_class = if options[:class_name].is_a?(Class)
69
- options[:class_name]
70
- else
71
- options[:class_name].constantize
72
- end
57
+ def add_enumeration(reflection)
58
+ define_getter_method(reflection)
59
+ define_setter_method(reflection)
60
+ define_bang_methods(reflection)
61
+ define_scopes(reflection)
73
62
 
74
- enumerator_class.find(send(options[:foreign_key]))
63
+ self._enumerations += [reflection]
64
+ end
65
+
66
+ # Getter for belongs_to
67
+ #
68
+ # Example:
69
+ #
70
+ # user.role_id = 1
71
+ # user.role => #<Enumerations::Value: @base=Role, @symbol=:admin...>
72
+ #
73
+ def define_getter_method(reflection)
74
+ define_method(reflection.name) do
75
+ reflection.enumerator_class.find(send(reflection.foreign_key))
76
+ end
77
+ end
78
+
79
+ # Setter for belongs_to
80
+ #
81
+ # Example:
82
+ #
83
+ # user.role = Role.admin
84
+ # user.role_id => 1
85
+ #
86
+ def define_setter_method(reflection)
87
+ define_method("#{reflection.name}=") do |other|
88
+ send("#{reflection.foreign_key}=", other.id)
75
89
  end
90
+ end
76
91
 
77
- # Setter for belongs_to
78
- #
79
- # Example:
80
- #
81
- # user.role = Role.admin
82
- # user.role_id => 1
83
- #
84
- define_method "#{name}=" do |other|
85
- send("#{options[:foreign_key]}=", other.id)
92
+ # Add bang methods for setting all enumeration values.
93
+ # All methods are prefixed with enumeration name.
94
+ #
95
+ # Example:
96
+ #
97
+ # user.role_admin!
98
+ # user.role => #<Enumerations::Value: @base=Role, @symbol=:admin...>
99
+ #
100
+ def define_bang_methods(reflection)
101
+ reflection.enumerator_class.all.each do |enumeration|
102
+ define_method("#{reflection.name}_#{enumeration.to_sym}!") do
103
+ send("#{reflection.name}=", enumeration)
104
+ end
86
105
  end
106
+ end
87
107
 
88
- self._enumerations += [Reflection.new(name, options)]
108
+ # Scopes for enumerated ActiveRecord model.
109
+ # Format of scope name is with_#{enumeration_name}_#{enumeration_value_name}.
110
+ #
111
+ # Example:
112
+ #
113
+ # User.with_role_admin => <#ActiveRecord::Relation []>
114
+ # User.with_role_editor => <#ActiveRecord::Relation []>
115
+ #
116
+ def define_scopes(reflection)
117
+ reflection.enumerator_class.all.each do |enumeration|
118
+ scope "with_#{reflection.name}_#{enumeration.symbol}",
119
+ -> { where(reflection.foreign_key => enumeration.id) }
120
+ end
89
121
  end
90
122
  end
91
123
  end
92
124
 
93
125
  # Extend ActiveRecord with Enumeration capabilites
94
126
  ActiveSupport.on_load(:active_record) do
95
- include Enumeration
127
+ include Enumerations
96
128
  end
@@ -1,8 +1,13 @@
1
1
  require 'active_support/core_ext/class/attribute'
2
2
  require 'active_support/core_ext/string/inflections'
3
+ require 'enumerations/value'
4
+ require 'enumerations/finder_methods'
3
5
 
4
- module Enumeration
6
+ module Enumerations
5
7
  class Base
8
+ extend Enumerations::FinderMethods
9
+ include Enumerations::Value
10
+
6
11
  class_attribute :_values, :_symbol_index
7
12
  self._values = {}
8
13
  self._symbol_index = {}
@@ -13,13 +18,11 @@ module Enumeration
13
18
  #
14
19
  # value :admin, id: 1, name: 'Admin', description: 'Some description...'
15
20
  #
16
- # Role.admin.id => # 1
17
- # Role.find(:admin).name => # "Admin"
18
- # Role.find(1).description => # "Some description..."
21
+ # Role.admin.id => # 1
22
+ # Role.find(:admin).name => # "Admin"
23
+ # Role.find(1).description => # "Some description..."
19
24
  #
20
25
  def self.value(symbol, attributes)
21
- # TODO: make this errors better if needed
22
- # TODO: test this errors
23
26
  raise 'Enumeration id is required' if attributes[:id].nil?
24
27
  raise "Duplicate symbol #{symbol}" if find(symbol)
25
28
  raise "Duplicate id #{attributes[:id]}" if find(attributes[:id])
@@ -31,8 +34,8 @@ module Enumeration
31
34
  #
32
35
  # Example:
33
36
  #
34
- # Role.admin => #<Enumeration::Value:0x007fff45d7ec30 @base=Role, @symbol=:admin...>
35
- # Role.staff => #<Enumeration::Value:0x007f980e9cb0a0 @base=Role, @symbol=:staff...>
37
+ # Role.admin => #<Enumerations::Value: @base=Role, @symbol=:admin...>
38
+ # Role.staff => #<Enumerations::Value: @base=Role, @symbol=:staff...>
36
39
  #
37
40
  singleton_class.send(:define_method, symbol) do
38
41
  find(symbol)
@@ -71,117 +74,21 @@ module Enumeration
71
74
  #
72
75
  # Example:
73
76
  #
74
- # Role.all => # [#<Enumeration::Value:0x007f8ed7f46100 @base=Role, @symbol=:admin...>,
75
- # #<Enumeration::Value:0x007f8ed7f45de0 @base=Role, @symbol=:manager...>,
76
- # #<Enumeration::Value:0x007f8ed7f45ae8 @base=Role, @symbol=:staff...>]
77
+ # Role.all => # [#<Enumerations::Value: @base=Role, @symbol=:admin...>,
78
+ # #<Enumerations::Value: @base=Role, @symbol=:manager...>,
79
+ # #<Enumerations::Value: @base=Role, @symbol=:staff...>]
77
80
  #
78
81
  def self.all
79
82
  _values.values
80
83
  end
81
84
 
82
- # Finds an enumeration by symbol, id or name
83
- #
84
- # Example:
85
- #
86
- # Role.find(:admin) => #<Enumeration::Value:0x007f8ed7f46100 @base=Role, @symbol=:admin...>
87
- # Role.find(2) => #<Enumeration::Value:0x007f8ed7f45de0 @base=Role, @symbol=:manager...>
88
- # Role.find('2') => #<Enumeration::Value:0x007f8ed7f45de0 @base=Role, @symbol=:manager...>
89
- # Role.find('staff') => #<Enumeration::Value:0x007f8ed7f45ae8 @base=Role, @symbol=:staff...>
90
- #
91
- def self.find(key)
92
- case key
93
- when Symbol then find_by_key(key)
94
- when String then find_by_key(key.to_sym) || find_by_id(key.to_i)
95
- when Integer then find_by_id(key)
96
- end
97
- end
98
-
99
- # Finds an enumeration by defined attribute. Simmilar to AcriveRecord::FinderMethods#find_by
100
- #
101
- # Example:
102
- #
103
- # Role.find_by(name: 'Admin') => #<Enumeration::Value:0x007f8ed7f46100 @base=Role, @symbol=:admin...>
104
- #
105
- def self.find_by(**args)
106
- _values.values.find { |value| args.map { |k, v| value.send(k) == v }.all? }
107
- end
108
-
109
- def self.find_by_key(key)
110
- _values[key]
111
- end
112
-
113
- def self.find_by_id(id)
114
- _values[_symbol_index.key(id)]
115
- end
85
+ attr_reader :symbol
116
86
 
117
87
  def initialize(symbol, attributes)
118
88
  @symbol = symbol
119
89
  @attributes = attributes
120
- create_instance_methods
121
- end
122
90
 
123
- attr_reader :symbol
124
-
125
- def to_i
126
- id
127
- end
128
-
129
- def to_s
130
- name
131
- end
132
-
133
- def to_sym
134
- @symbol
135
- end
136
-
137
- def to_param
138
- id
139
- end
140
-
141
- # Comparison by id, symbol or object
142
- #
143
- # Example:
144
- #
145
- # Role.admin == 1 => true
146
- # Role.admin == :admin => true
147
- # Role.admin == Role.admin => true
148
- # Role.admin == 2 => false
149
- # Role.admin == :staff => false
150
- # Role.admin == Role.staff => false
151
- #
152
- # TODO: test if case..when is working with this
153
- def ==(other)
154
- case other
155
- when Integer then other == id
156
- when Symbol then other == @symbol
157
- else super
158
- end
159
- end
160
-
161
- private
162
-
163
- # Getters for all attributes
164
- #
165
- # Example:
166
- #
167
- # Role.admin => #<Enumeration::Value:0x007fff45d7ec30 @base=Role, @symbol=:admin,
168
- # @attributes={:id=>1, :name=>"Admin", :description=>"Some description..."}>
169
- # user.role.id => # 1
170
- # user.role.name => # "Admin"
171
- # user.role.description => # "Some description..."
172
- # user.role.admin? => # true
173
- # user.role.staff? => # false
174
- #
175
- def create_instance_methods
176
- @attributes.each do |key, _|
177
- self.class.send :define_method, key do
178
- @attributes[key]
179
- end
180
- end
181
-
182
- self.class.send :define_method, "#{@symbol}?" do
183
- __callee__[0..-2].to_sym == @symbol
184
- end
91
+ create_instance_methods
185
92
  end
186
93
  end
187
94
  end
@@ -0,0 +1,38 @@
1
+ module Enumerations
2
+ module FinderMethods
3
+ # Finds an enumeration by symbol, id or name
4
+ #
5
+ # Example:
6
+ #
7
+ # Role.find(:admin) => #<Enumerations::Value: @base=Role, @symbol=:admin...>
8
+ # Role.find(2) => #<Enumerations::Value: @base=Role, @symbol=:manager...>
9
+ # Role.find('2') => #<Enumerations::Value: @base=Role, @symbol=:manager...>
10
+ # Role.find('staff') => #<Enumerations::Value: @base=Role, @symbol=:staff...>
11
+ #
12
+ def find(key)
13
+ case key
14
+ when Symbol then find_by_key(key)
15
+ when String then find_by_key(key.to_sym) || find_by_id(key.to_i)
16
+ when Fixnum then find_by_id(key)
17
+ end
18
+ end
19
+
20
+ # Finds an enumeration by defined attribute. Similar to ActiveRecord::FinderMethods#find_by
21
+ #
22
+ # Example:
23
+ #
24
+ # Role.find_by(name: 'Admin') => #<Enumerations::Value: @base=Role, @symbol=:admin...>
25
+ #
26
+ def find_by(**args)
27
+ _values.values.find { |value| args.map { |k, v| value.send(k) == v }.all? }
28
+ end
29
+
30
+ def find_by_key(key)
31
+ _values[key]
32
+ end
33
+
34
+ def find_by_id(id)
35
+ _values[_symbol_index.key(id)]
36
+ end
37
+ end
38
+ end
@@ -1,18 +1,22 @@
1
- module Enumeration
1
+ module Enumerations
2
2
  class Reflection
3
3
  attr_reader :name
4
4
 
5
- def initialize(name, options)
5
+ def initialize(name, options = {})
6
6
  @name = name
7
7
  @options = options
8
8
  end
9
9
 
10
10
  def class_name
11
- @options[:class_name]
11
+ @class_name ||= (@options[:class_name] || name).to_s.camelize
12
12
  end
13
13
 
14
14
  def foreign_key
15
- @options[:foreign_key]
15
+ @foreign_key ||= (@options[:foreign_key] || "#{name}_id").to_sym
16
+ end
17
+
18
+ def enumerator_class
19
+ @enumerator_class ||= class_name.constantize
16
20
  end
17
21
  end
18
22
  end
@@ -0,0 +1,80 @@
1
+ module Enumerations
2
+ module Value
3
+ def to_i
4
+ id
5
+ end
6
+
7
+ def to_s
8
+ name
9
+ end
10
+
11
+ def to_sym
12
+ symbol
13
+ end
14
+
15
+ def to_param
16
+ id
17
+ end
18
+
19
+ # Comparison by id, symbol or object
20
+ #
21
+ # Example:
22
+ #
23
+ # Role.admin == 1 => true
24
+ # Role.admin == :admin => true
25
+ # Role.admin == Role.admin => true
26
+ # Role.admin == 2 => false
27
+ # Role.admin == :staff => false
28
+ # Role.admin == Role.staff => false
29
+ #
30
+ # TODO: test if case..when is working with this
31
+ def ==(other)
32
+ case other
33
+ when Fixnum then other == id
34
+ when Symbol then other == symbol
35
+ else super
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def create_instance_methods
42
+ define_attributes_getters
43
+ define_value_checking_method
44
+ end
45
+
46
+ # Getters for all attributes
47
+ #
48
+ # Example:
49
+ #
50
+ # Role.admin => #<Enumerations::Value:0x007fff45d7ec30 @base=Role, @symbol=:admin,
51
+ # @attributes={:id=>1, :name=>"Admin", :description=>"Some description..."}>
52
+ # user.role.id => # 1
53
+ # user.role.name => # "Admin"
54
+ # user.role.description => # "Some description..."
55
+ #
56
+ def define_attributes_getters
57
+ @attributes.each do |key, _|
58
+ next if respond_to?(key)
59
+
60
+ self.class.send :define_method, key do
61
+ @attributes[key]
62
+ end
63
+ end
64
+ end
65
+
66
+ # Predicate methods for values
67
+ #
68
+ # Example:
69
+ #
70
+ # user.role = Role.admin
71
+ # user.role.admin? => # true
72
+ # user.role.staff? => # false
73
+ #
74
+ def define_value_checking_method
75
+ self.class.send :define_method, "#{symbol}?" do
76
+ __callee__[0..-2].to_sym == symbol
77
+ end
78
+ end
79
+ end
80
+ end
@@ -1,3 +1,3 @@
1
- module Enumeration
2
- VERSION = '1.3.2'
1
+ module Enumerations
2
+ VERSION = '2.0.0'
3
3
  end
data/test/base_test.rb CHANGED
@@ -13,6 +13,18 @@ class BaseTest < Minitest::Test
13
13
  refute_same :published, status.symbol
14
14
  end
15
15
 
16
+ def test_lookup_by_string_id
17
+ status = Status.find('1')
18
+
19
+ assert_equal :draft, status.symbol
20
+ end
21
+
22
+ def test_lookup_by_string_key
23
+ status = Status.find('draft')
24
+
25
+ assert_equal :draft, status.symbol
26
+ end
27
+
16
28
  def test_find_by
17
29
  status = Status.find_by(name: 'Draft')
18
30
 
@@ -32,6 +44,19 @@ class BaseTest < Minitest::Test
32
44
  assert_equal statuses.first, Status.draft
33
45
  end
34
46
 
47
+ def test_symbols
48
+ status_symbols = Status.symbols
49
+
50
+ assert_equal 5, status_symbols.size
51
+ assert_equal status_symbols.first, Status.draft.to_sym
52
+ end
53
+
54
+ def test_required_id
55
+ assert_raises 'Enumeration id is required' do
56
+ Class.new.value draft: { name: 'Draft' }
57
+ end
58
+ end
59
+
35
60
  def test_duplicated_id
36
61
  assert_raises 'Duplicate id 1' do
37
62
  Class.new.values draft: { id: 1, name: 'Draft' },
@@ -57,45 +82,17 @@ class BaseTest < Minitest::Test
57
82
  end
58
83
  end
59
84
 
60
- def test_with_defined_custom_attributes_visible
61
- status = Status.find(:none)
85
+ def test_enumerations_custom_instance_method
86
+ role = Role.find(:admin)
62
87
 
63
- assert_equal true, status.visible
88
+ assert_equal 'user_Admin', role.my_custom_name
64
89
  end
65
90
 
66
- def test_with_defined_custom_attributes_deleted
67
- status = Status.find(:deleted)
68
-
69
- assert_equal true, status.deleted
70
- end
91
+ def test_all_enumerations_has_custom_instance_methods
92
+ roles = Role.all
71
93
 
72
- def test_without_defined_custom_attributes
73
- status = Status.find(:draft)
74
-
75
- assert_equal nil, status.visible
76
- end
77
-
78
- def test_equal_by_id
79
- status = Status.find(:draft)
80
-
81
- assert_equal true, status == 1
82
- end
83
-
84
- def test_equal_by_symbol
85
- status = Status.draft
86
-
87
- assert_equal true, status == :draft
88
- end
89
-
90
- def test_equal_by_enumeration
91
- status = Status.draft
92
-
93
- assert_equal true, status == Status.draft
94
- end
95
-
96
- def test_not_equal_by_enumeration
97
- status = Status.draft
98
-
99
- assert_equal false, status == Status.published
94
+ assert_silent do
95
+ roles.map(&:my_custom_name)
96
+ end
100
97
  end
101
98
  end
@@ -0,0 +1,15 @@
1
+ require 'logger'
2
+
3
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
4
+
5
+ ActiveRecord::Schema.define do
6
+ create_table :posts, force: true do |t|
7
+ t.integer :status_id
8
+ t.integer :some_other_status_id
9
+ end
10
+
11
+ create_table :users, force: true do |t|
12
+ t.integer :role_id
13
+ t.string :status_id
14
+ end
15
+ end
@@ -18,6 +18,20 @@ class EnumerationsTest < Minitest::Test
18
18
  assert_equal 'Draft', p.status.to_s
19
19
  end
20
20
 
21
+ def test_model_bang_assignment
22
+ p = Post.new
23
+ p.status_draft!
24
+
25
+ assert_equal 'Draft', p.status.to_s
26
+ end
27
+
28
+ def test_model_bang_assignment_with_custom_name
29
+ p = Post.new
30
+ p.different_status_draft!
31
+
32
+ assert_equal 'Draft', p.different_status.to_s
33
+ end
34
+
21
35
  def test_model_via_id_assignment
22
36
  p = Post.new
23
37
  p.some_other_status_id = Status.published.id
@@ -38,4 +52,37 @@ class EnumerationsTest < Minitest::Test
38
52
 
39
53
  assert_equal false, p.status.published?
40
54
  end
55
+
56
+ def test_multiple_enumerations_on_model
57
+ enumerations = User.reflect_on_all_enumerations
58
+
59
+ assert_equal 2, enumerations.size
60
+
61
+ assert_equal :role, enumerations.first.name
62
+ assert_equal :role_id, enumerations.first.foreign_key
63
+
64
+ assert_equal :status, enumerations[1].name
65
+ assert_equal :status_id, enumerations[1].foreign_key
66
+ end
67
+
68
+ def test_multiple_enumeration_assignments_on_model
69
+ u = User.new
70
+ u.role = Role.admin
71
+ u.status = Status.published
72
+
73
+ assert_equal 'Admin', u.role.to_s
74
+ assert_equal 'Published', u.status.to_s
75
+ end
76
+
77
+ def test_enumerated_class_has_scopes
78
+ Role.all do |role|
79
+ assert_respond_to User, ['with_role', role.name].join('_').to_sym
80
+ end
81
+ end
82
+
83
+ def test_enumerated_class_scope_hash_value
84
+ query_hash = User.with_role_admin.where_values_hash.symbolize_keys
85
+
86
+ assert_equal query_hash, role_id: 1
87
+ end
41
88
  end
@@ -1,11 +1,38 @@
1
1
  require_relative 'test_helper'
2
2
 
3
3
  class ReflectionTest < Minitest::Test
4
- def test_reflections
5
- reflection = Enumeration::Reflection.new(:role, class_name: 'Role', foreign_key: :role_id)
4
+ def test_reflection_with_all_attributes
5
+ reflection = Enumerations::Reflection.new(:status, class_name: 'Status',
6
+ foreign_key: :status_id)
6
7
 
7
- assert_equal :role, reflection.name
8
- assert_equal 'Role', reflection.class_name
9
- assert_equal :role_id, reflection.foreign_key
8
+ assert_equal :status, reflection.name
9
+ assert_equal 'Status', reflection.class_name
10
+ assert_equal :status_id, reflection.foreign_key
11
+ assert_equal ::Status, reflection.enumerator_class
12
+ end
13
+
14
+ def test_reflection_without_class_name_and_foreign_key
15
+ reflection = Enumerations::Reflection.new(:status)
16
+
17
+ assert_equal :status, reflection.name
18
+ assert_equal 'Status', reflection.class_name
19
+ assert_equal :status_id, reflection.foreign_key
20
+ assert_equal ::Status, reflection.enumerator_class
21
+ end
22
+
23
+ def test_reflection_with_custom_name_and_without_foreign_key
24
+ reflection = Enumerations::Reflection.new(:my_status, class_name: 'Status')
25
+
26
+ assert_equal :my_status, reflection.name
27
+ assert_equal 'Status', reflection.class_name
28
+ assert_equal :my_status_id, reflection.foreign_key
29
+ assert_equal ::Status, reflection.enumerator_class
30
+ end
31
+
32
+ def test_reflection_with_class_name_as_constant
33
+ reflection = Enumerations::Reflection.new(:status, class_name: Status)
34
+
35
+ assert_equal 'Status', reflection.class_name
36
+ assert_equal ::Status, reflection.enumerator_class
10
37
  end
11
38
  end
data/test/test_helper.rb CHANGED
@@ -1,14 +1,14 @@
1
- # TODO: improve tests
1
+ require 'codeclimate-test-reporter'
2
+ CodeClimate::TestReporter.start
3
+
2
4
  require 'minitest/autorun'
3
5
  require 'enumerations'
6
+ require 'active_record'
4
7
  require 'pry'
5
8
 
6
- # Faking ActiveRecord
7
- class MockActiveRecordBase
8
- include Enumeration
9
- end
9
+ require_relative 'database_helper'
10
10
 
11
- class Status < Enumeration::Base
11
+ class Status < Enumerations::Base
12
12
  values draft: { id: 1, name: 'Draft' },
13
13
  review_pending: { id: 2, name: 'Review pending' },
14
14
  published: { id: 3, name: 'Published' }
@@ -17,9 +17,26 @@ class Status < Enumeration::Base
17
17
  value :deleted, id: 5, deleted: true
18
18
  end
19
19
 
20
- class Post < MockActiveRecordBase
20
+ class Role < Enumerations::Base
21
+ value :admin, id: 1, name: 'Admin', admin: true
22
+ value :editor, id: 2, name: 'Editor'
23
+ value :author, id: 3, name: 'Author'
24
+
25
+ def my_custom_name
26
+ ['user', name].join('_')
27
+ end
28
+ end
29
+
30
+ class Post < ActiveRecord::Base
21
31
  attr_accessor :status_id, :some_other_status_id
22
32
 
23
33
  enumeration :status
24
34
  enumeration :different_status, foreign_key: :some_other_status_id, class_name: 'Status'
25
35
  end
36
+
37
+ class User < ActiveRecord::Base
38
+ attr_accessor :role_id, :status_id
39
+
40
+ enumeration :role
41
+ enumeration :status
42
+ end
@@ -0,0 +1,63 @@
1
+ require_relative 'test_helper'
2
+
3
+ class ValueTest < Minitest::Test
4
+ def test_equal_by_id
5
+ status = Status.find(:draft)
6
+
7
+ assert_equal true, status == 1
8
+ end
9
+
10
+ def test_equal_by_symbol
11
+ status = Status.draft
12
+
13
+ assert_equal true, status == :draft
14
+ end
15
+
16
+ def test_equal_by_enumeration
17
+ status = Status.draft
18
+
19
+ assert_equal true, status == Status.draft
20
+ end
21
+
22
+ def test_not_equal_by_enumeration
23
+ status = Status.draft
24
+
25
+ assert_equal false, status == Status.published
26
+ end
27
+
28
+ def test_with_defined_custom_attributes_visible
29
+ status = Status.find(:none)
30
+
31
+ assert_equal true, status.visible
32
+ end
33
+
34
+ def test_with_defined_custom_attributes_deleted
35
+ status = Status.find(:deleted)
36
+
37
+ assert_equal true, status.deleted
38
+ end
39
+
40
+ def test_without_defined_custom_attributes
41
+ status = Status.find(:draft)
42
+
43
+ assert_equal nil, status.visible
44
+ end
45
+
46
+ def test_enumeration_to_i
47
+ status = Status.find(:draft)
48
+
49
+ assert_equal status.to_i, 1
50
+ end
51
+
52
+ def test_enumeration_to_sym
53
+ status = Status.find(:draft)
54
+
55
+ assert_equal status.to_sym, :draft
56
+ end
57
+
58
+ def test_enumeration_to_param
59
+ status = Status.find(:draft)
60
+
61
+ assert_equal status.to_param, 1
62
+ end
63
+ end
data/test/version_test.rb CHANGED
@@ -2,6 +2,6 @@ require_relative 'test_helper'
2
2
 
3
3
  class VersionTest < Minitest::Test
4
4
  def test_version
5
- assert_equal '1.3.0', Enumeration::VERSION
5
+ assert_equal '2.0.0', Enumerations::VERSION
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enumerations
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomislav Car
8
8
  - Nikica Jokic
9
9
  - Nikola Santic
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2010-08-20 00:00:00.000000000 Z
13
+ date: 2016-08-15 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -54,6 +54,48 @@ dependencies:
54
54
  - - ">="
55
55
  - !ruby/object:Gem::Version
56
56
  version: '0'
57
+ - !ruby/object:Gem::Dependency
58
+ name: rake
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ - !ruby/object:Gem::Dependency
72
+ name: codeclimate-test-reporter
73
+ requirement: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ - !ruby/object:Gem::Dependency
86
+ name: sqlite3
87
+ requirement: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ type: :development
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
57
99
  description: Extends ActiveRecord with enumeration capabilites.
58
100
  email:
59
101
  - tomislav@infinum.hr
@@ -64,24 +106,27 @@ extensions: []
64
106
  extra_rdoc_files: []
65
107
  files:
66
108
  - ".gitignore"
67
- - ".travis.yml"
68
109
  - Gemfile
69
110
  - Rakefile
70
111
  - Readme.md
71
112
  - enumerations.gemspec
72
113
  - lib/enumerations.rb
73
114
  - lib/enumerations/base.rb
115
+ - lib/enumerations/finder_methods.rb
74
116
  - lib/enumerations/reflection.rb
117
+ - lib/enumerations/value.rb
75
118
  - lib/enumerations/version.rb
76
119
  - test/base_test.rb
120
+ - test/database_helper.rb
77
121
  - test/enumerations_test.rb
78
122
  - test/reflection_test.rb
79
123
  - test/test_helper.rb
124
+ - test/value_test.rb
80
125
  - test/version_test.rb
81
126
  homepage: https://github.com/infinum/enumerations
82
127
  licenses: []
83
128
  metadata: {}
84
- post_install_message:
129
+ post_install_message:
85
130
  rdoc_options: []
86
131
  require_paths:
87
132
  - lib
@@ -96,13 +141,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
96
141
  - !ruby/object:Gem::Version
97
142
  version: '0'
98
143
  requirements: []
99
- rubygems_version: 3.0.3
100
- signing_key:
144
+ rubyforge_project:
145
+ rubygems_version: 2.5.1
146
+ signing_key:
101
147
  specification_version: 4
102
148
  summary: Enumerations for ActiveRecord!
103
149
  test_files:
104
150
  - test/base_test.rb
151
+ - test/database_helper.rb
105
152
  - test/enumerations_test.rb
106
153
  - test/reflection_test.rb
107
154
  - test/test_helper.rb
155
+ - test/value_test.rb
108
156
  - test/version_test.rb
data/.travis.yml DELETED
@@ -1,5 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.1.0
4
- - 2.3.1
5
- script: rake