enum_ext 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d99346b1ae5f9458733025608cad6e8a1ab427091ce44d10a544e880722633c
4
- data.tar.gz: 6a1943ddedaa37022bdfe421dbc4c5d063c63149a96aaa0f05cdab35f423de6b
3
+ metadata.gz: efd427aa71da1e4f38c9ee7837d170ef9732a709dc23a80332d7d61456632350
4
+ data.tar.gz: 42e2acb52324970fb199cf036c5763f7c4d4c8ce5e7fdd8c7fca80dc08913807
5
5
  SHA512:
6
- metadata.gz: ce540db8aca9002c6a46a5ae5eb7a45f7a296d4fd183493a8796e3b9dd007ebb04bc0793b1162b82e177de5b59ff06e8e553248a2aa4c725b17d3570d682444f
7
- data.tar.gz: 7db85461bd47c03b3169259f699a29e7a1855fd791d53fb4fe84995b812739fe4968b8184665dfd04230b71e2d78152dc8868f78f89452f37d6b20ed00c77ecc
6
+ metadata.gz: 3c1aaf8307cba00ba948a79f2ceee1acd09dd1b310c9ee22c892c5e776d63716addcb3e2f3c505146b98c206fdc9f8134309a58b268c323e7df697f380221650
7
+ data.tar.gz: e7ea79641953c863d45427c3a5eca6a942089a9cfb1f796ddc54a0fd5dbb275ca598d172d03f61ded14e5a5751c6cdca44423053c3acfb1ecdf3d87db542fa68
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # 0.9
2
+ * supersets works fine and same way with prefixes and suffixes as usual enum does
3
+
4
+ # 0.8.1
5
+ * Fixes issue https://github.com/alekseyl/enum_ext/issues/50
6
+ * Better describe for supersets.
7
+ * Multiple readme and comments fixes
8
+
1
9
  # 0.8.0
2
10
  * Methods annotations added:
3
11
  * Full descriptions: Class.enum.describe(short=true) / Class.enum.describe_short / Class.enum.describe_long / Class.enum.describe_basic
data/Gemfile_rails_6.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- enum_ext (0.8.0)
4
+ enum_ext (0.9.0)
5
5
  activerecord (>= 5.2.4.3)
6
6
 
7
7
  GEM
@@ -82,6 +82,7 @@ PLATFORMS
82
82
  ruby
83
83
 
84
84
  DEPENDENCIES
85
+ activerecord (< 7)
85
86
  amazing_print
86
87
  bundler (>= 1.11)
87
88
  byebug
data/README.md CHANGED
@@ -7,7 +7,7 @@ EnumExt extends rails enum with localization/translation and it's helpers, mass-
7
7
  Add this line to your application's Gemfile:
8
8
 
9
9
  ```ruby
10
- gem 'enum_ext', '~> 0.7'
10
+ gem 'enum_ext', '~> 0.8'
11
11
  ```
12
12
 
13
13
  And then execute:
@@ -26,12 +26,12 @@ Or install it yourself as:
26
26
 
27
27
  class SomeModel
28
28
  extend EnumExt
29
-
30
- enum kinds: {}, ext: [:enum_i, :enum_mass_assign, ]
31
- humanize_enum #...
32
- translate_enum #...
33
- ext_enum_sets #...
34
- end
29
+
30
+ enum status: {}, ext: [:enum_i, :enum_mass_assign, enum_supersets: { superset: [:basic_enum] } ]
31
+ humanize_enum #...
32
+ translate_enum #...
33
+ ext_enum_sets # if needed
34
+ end
35
35
  ```
36
36
 
37
37
  Let's assume that we have model Request representing some buying requests with enum **status**, and we have model Order with requests,
@@ -56,16 +56,16 @@ This is a preferable way now, and old helpers are private starting version 0.6!:
56
56
 
57
57
  ```ruby
58
58
  #Instead of three method calls:
59
- enum kind: {}
60
- enum_i :kind # will raise an private method error starting ver 0.6
61
- enum_mass_assign :kind # will raise an private method error starting ver 0.6
59
+ enum status: {}
60
+ enum_i :status # will raise an private method error starting ver 0.6
61
+ enum_mass_assign :status # will raise an private method error starting ver 0.6!!!
62
62
 
63
63
  #You should go with ext option instead:
64
- enum kinds: {}, ext: [:enum_i, :enum_mass_assign]
64
+ enum status: {}, ext: [:enum_i, :enum_mass_assign]
65
65
 
66
66
  # OR in case of standalone enum definition:
67
- enum kinds: {} # somewhere where you can't or don't want reach
68
- enum_ext :kinds, [:enum_i, :enum_mass_assign, enum_supersets: {} ]
67
+ enum status: {} # somewhere where you can't or don't want to reach
68
+ enum_ext :status, [:enum_i, :enum_mass_assign, enum_supersets: {} ]
69
69
  ```
70
70
  Rem: enum_ext could be called multiple times and merge later definitions, though I can't imagine why would you split it to multiple calls.
71
71
 
@@ -75,10 +75,10 @@ Rem: The only exceptions for the new syntax are full translation/humanization he
75
75
 
76
76
  ```ruby
77
77
  # GOOD:
78
- enum_ext :kinds, [:enum_i, :enum_mass_assign, :translate_enum, enum_supersets: {}]
78
+ enum_ext :status, [:enum_i, :enum_mass_assign, :translate_enum, enum_supersets: {}]
79
79
 
80
80
  # BAD (even if correctly defines internationalization):
81
- enum_ext :kinds, [:enum_i, :enum_mass_assign, :translate_enum, enum_supersets: {}] do
81
+ enum_ext :status, [:enum_i, :enum_mass_assign, :translate_enum, enum_supersets: {}] do
82
82
  I18n.t("scope.#{kind}")
83
83
  end
84
84
  ```
@@ -87,7 +87,7 @@ Rem: The only exceptions for the new syntax are full translation/humanization he
87
87
 
88
88
  ### Humanization (humanize_enum)
89
89
 
90
- if app doesn't need internationalization, it may use humanize_enum to make enum user friendly
90
+ If app doesn't need internationalization, it may use humanize_enum to make enum output user friendly
91
91
 
92
92
  ```ruby
93
93
  humanize_enum :status, {
@@ -103,14 +103,13 @@ Rem: The only exceptions for the new syntax are full translation/humanization he
103
103
  ```
104
104
 
105
105
  This humanize_enum adds to instance:
106
- - t_in_cart, t_paid, t_ready_for_shipment
106
+ - t_status
107
107
 
108
- and to class:
109
- - t_statuses - as given or generated values
110
- - t_statuses_options - translated enum values options for select input
111
- - t_statuses_options_i - same as above but use int values with translations works for ActiveAdmin filters for instance
108
+ and to enum object:
109
+ - statuses.t_options - translated enum values options for select input
110
+ - statuses.t_options_i - same as above but use int values with translations works for ActiveAdmin filters for instance
111
+
112
112
 
113
-
114
113
  Example with block:
115
114
 
116
115
  ```ruby
@@ -122,12 +121,12 @@ Rem: The only exceptions for the new syntax are full translation/humanization he
122
121
  Example for select:
123
122
 
124
123
  ```ruby
125
- f.select :status, Request.t_statuses_options
124
+ f.select :status, Request.statuses.t_options
126
125
  ```
127
126
 
128
127
  in Active Admin filters
129
128
  ```ruby
130
- filter :status, as: :select, label: 'Status', collection: Request.t_statuses_options_i
129
+ filter :status, as: :select, label: 'Status', collection: Request.statuses.t_options_i
131
130
  ```
132
131
 
133
132
  **Rem:** select options may break when using lambda() or proc with instance method, but will survive with block
@@ -138,7 +137,7 @@ Rem: The only exceptions for the new syntax are full translation/humanization he
138
137
  request.paid!
139
138
  request.status # >> paid
140
139
  request.t_status # >> "paid 3 dollars"
141
- Request.t_statuses # >> { in_cart: -> { I18n.t("request.status.in_cart") }, .... }
140
+ Request.statuses.localizations # >> { in_cart: -> { I18n.t("request.status.in_cart") }, .... }
142
141
  ```
143
142
 
144
143
  Could be called multiple times, all humanization definitions will be merged under the hood.
@@ -158,6 +157,8 @@ Or it can be done with block either with translate or humanize:
158
157
  end
159
158
  ```
160
159
 
160
+ All humanization examples also should work same way as expected.
161
+
161
162
  ## Enum extended functionality
162
163
 
163
164
  ### Enum to_i shortcut ( enum_i )
@@ -172,6 +173,8 @@ Defines method enum_name_i shortcut for Model.enum_names[elem.enum_name] or enum
172
173
  request.paid_i # 10
173
174
  ```
174
175
 
176
+ Rem: whenever underlying enum is not an integer will refuse to define helper and outputs WARNING
177
+
175
178
  ### Enum SuperSets (enum_supersets)
176
179
 
177
180
  **Use-case** whenever you need superset of enums to behave like a super enum.
@@ -185,16 +188,16 @@ Defines method enum_name_i shortcut for Model.enum_names[elem.enum_name] or enum
185
188
  ```ruby
186
189
  enum status: [:in_cart, :waiting_for_payment, :paid, :packing, :ready_for_shipment, :on_delivery, :delivered],
187
190
  ext: [enum_supersets: {
188
- delivery_set: [:ready_for_shipment, :on_delivery], # for shipping department for example
191
+ around_delivery: [:ready_for_shipment, :on_delivery], # for shipping department for example
189
192
  in_warehouse: [:packing, :ready_for_shipment], # this scope is just for superposition example below
190
- sold: [:paid, :delivery_set, :in_warehouse, :delivered] # also you can define any superposition of already defined supersets or enum values
193
+ sold: [:paid, :around_delivery, :in_warehouse, :delivered] # also you can define any superposition of already defined supersets or enum values
191
194
  }]
192
195
 
193
196
  # supersets will be stored inside enum wrapper object, and can be de-referenced to basic enum values
194
197
  # using wrapper defined methods: "superset_enum_plural", i.e. statuses.sold_statuses -> [:paid, :packing, :ready_for_shipment, :on_delivery, :delivered]
195
198
  # so new supersets could be defined using Array operations against newly defined methods
196
199
  enum_ext :status, enum_supersets: {
197
- outside_warehouse: ( statuses.delivery_set_statuses - statuses.in_warehouse_statuses ) #... any other array operations like &, + and so can be used
200
+ outside_warehouse: ( statuses.around_delivery - statuses.in_warehouse ) #... any other array operations like &, + and so can be used
198
201
  }
199
202
  ```
200
203
 
@@ -202,39 +205,38 @@ it will generate:
202
205
 
203
206
  ```
204
207
  instance:
205
- - methods: delivery_set?, in_warehouse?
208
+ - methods: around_delivery?, in_warehouse?
206
209
 
207
210
  class:
208
- - named scopes: delivery_set, in_warehouse
209
- - parametrized scopes: with_statuses, without_statuses ( available as a standalone extension now, and will not be included by default in a versionafter 0.5.0)
211
+ - named scopes: around_delivery, in_warehouse
210
212
 
211
213
  enum methods:
212
214
  - Class.statuses.supersets -- will output superset definition hash
213
215
  - Class.statuses.supersets_raw -- will output superset decompositions to basic enum types hash
214
216
 
215
- - Class.statuses.delivery_superset (=[:ready_for_shipment, :on_delivery, :delivered] ), in_warehouse_statuses
216
- - delivery_set_statuses_i (= [3,4,5]), in_warehouse_statuses_i (=[3])
217
+ - Class.statuses.around_delivery (=[:ready_for_shipment, :on_delivery, :delivered] ), in_warehouse_statuses
218
+ - around_delivery_statuses_i (= [3,4,5]), in_warehouse_statuses_i (=[3])
217
219
 
218
- translation helpers ( started with t_... ):
219
- - Class.statuses.t_delivery_set_options (= [['translation or humanization', :ready_for_shipment] ...] ) for select inputs purposes
220
- - Class.statuses.t_delivery_set_options_i (= [['translation or humanization', 3] ...]) same as above but with integer as value ( for example to use in Active admin filters )
220
+ translation helpers grouped for superset ( started with t_... ):
221
+ - Class.statuses.t_around_delivery_options (= [['translation or humanization', :ready_for_shipment] ...] ) for select inputs purposes
222
+ - Class.statuses.t_around_delivery_options_i (= [['translation or humanization', 3] ...]) same as above but with integer as value ( for example to use in Active admin filters )
221
223
  ```
222
224
 
223
225
  ```ruby
224
226
  request.on_delivery!
225
- request.delivery_set? # >> true
227
+ request.around_delivery? # >> true
226
228
 
227
- Request.delivery_set.exists?(request) # >> true
229
+ Request.around_delivery.exists?(request) # >> true
228
230
  Request.in_warehouse.exists?(request) # >> false
229
231
 
230
- Request.delivery_set_statuses # >> ["ready_for_shipment", "on_delivery", "delivered"]
232
+ Request.statuses.around_delivery # >> ["ready_for_shipment", "on_delivery", "delivered"]
231
233
  ```
232
234
  Rem:
233
235
  supersets creation could be called multiple times defining a superposition of already defined sets ( considering previous example ):
234
236
 
235
237
  ```ruby
236
238
  enum_ext :status, enum_supersets: {
237
- outside_wharehouse: ( delivery_set_statuses - in_warehouse_statuses )#... any other array operations like &, + and so can be used
239
+ outside_wharehouse: ( statuses.around_delivery_superset - statuses.in_warehouse_superset )#... any other array operations like &, + and so can be used
238
240
  }
239
241
  ```
240
242
 
@@ -242,8 +244,8 @@ Rem: you can refer previously defined set as usual kind in the same method call:
242
244
 
243
245
  ```ruby
244
246
  enum_ext :status, enum_supersets: {
245
- delivery_set: [:ready_for_shipment, :on_delivery, :delivered],
246
- not_in_cart: [:paid, :delivery_set] #
247
+ around_delivery: [:ready_for_shipment, :on_delivery, :delivered],
248
+ not_in_cart: [:paid, :around_delivery] #
247
249
  }
248
250
  ```
249
251
 
@@ -254,7 +256,7 @@ Rem: you can refer previously defined set as usual kind in the same method call:
254
256
  ext: [:multi_enum_scopes]
255
257
 
256
258
  # some place else:
257
- Request.with_statuses( :payed, :delivery_set ) # >> status IN (:payed, :ready_for_shipment, :on_delivery, :delivered)
259
+ Request.with_statuses( :payed, :around_delivery ) # >> status IN (:payed, :ready_for_shipment, :on_delivery, :delivered)
258
260
  Request.without_statuses( :payed, :in_warehouse ) # >> status NOT IN (:payed, :ready_for_shipment)
259
261
  ```
260
262
 
@@ -264,7 +266,7 @@ Rem: you can refer previously defined set as usual kind in the same method call:
264
266
 
265
267
  **Use-case:** it's often case when I need bulk update without callbacks, so it's gets frustrating to repeat:
266
268
  ```
267
- some_scope.update_all(status: Request.statuses[:new_status], update_at: Time.now)
269
+ some_scope.update_all(status: :new_status, update_at: Time.now)
268
270
  ```
269
271
  If you need callbacks you can do like this: some_scope.each(&:new_stat!) but if you don't need callbacks and you
270
272
  have hundreds and thousands of records to change at once you better call update_all
@@ -323,15 +325,19 @@ Starting version 0.6 added support for rails 7+ enum definitions, that's making
323
325
  Now testings are done via `docker-compose up`. Look closer to Dockerfiles and `docker-compose.yml`
324
326
  to get the idea how they working simultaneously without interference with each other.
325
327
 
328
+ Rem. I'm always freaking googling everytime I need to run single test so I'll just keep here:
329
+
330
+ ```ruby
331
+ rake test TEST=test/test_enum_ext.rb TESTOPTS="--name=/bb/"
332
+ ```
326
333
 
327
334
  ## Development
328
335
 
329
336
  ## TODO
330
337
  [] better support for suffix/prefix as enum does
331
- [] describe method to observe current extension
338
+ [] add global config and allow global extension
332
339
 
333
340
  ## Contributing
334
-
335
341
  Bug reports and pull requests are welcome on GitHub at https://github.com/alekseyl/enum_ext or by email: leshchuk@gmail.com
336
342
 
337
343
 
@@ -2,15 +2,15 @@
2
2
  # but have no idea how to do this in a super-neat way, so it a little bit chaotic and experimental
3
3
  module EnumExt::Annotated
4
4
 
5
- # call it to see what's your enum current opitons
5
+ # call it to see what's your enum current options are
6
6
  def describe_basic
7
7
  puts yellow( "Basic #{enum_name} definition: \n" )
8
8
  print_hash(enum_values)
9
9
  end
10
10
 
11
- # call it to see all enum extensions defined.
11
+ # call it to see which enum extensions are defined.
12
12
  def describe_long
13
- puts yellow( "\nEnumExt extensions:" )
13
+ puts yellow( "\n\nEnumExt extensions:" )
14
14
 
15
15
  puts [
16
16
  describe_enum_i(false),
@@ -80,10 +80,19 @@ module EnumExt::Annotated
80
80
  description = if enabled_features[:supersets].blank?
81
81
  red( "\nSupersets not used!\n" )
82
82
  else
83
+ superset_method = enabled_features[:supersets].keys.first
83
84
  red( "\nSupersets definitions:\n" ) << inspect_hash(enabled_features[:supersets]) << <<~SUPERSETS
85
+
84
86
  # Instance methods added: #{enabled_features[:supersets].keys.join("?, ")}?
85
-
86
- # Class level methods added: #{enabled_features[:supersets].keys.join(", ")}
87
+ # Usage:
88
+ #{black("instance")}.#{cyan(superset_method)}?
89
+ # Will be equal true if any of: #{supersets_raw[superset_method].join("?, ")}? is true
90
+
91
+ # Class level methods/scopes added: #{enabled_features[:supersets].keys.join(", ")}
92
+ # Usage:
93
+ #{black(base_class.to_s)}.#{cyan(superset_method)}
94
+ # Will be getting all instances with #{enum_name} equals to any of: #{supersets_raw[superset_method].join(", ")}
95
+
87
96
  SUPERSETS
88
97
  end
89
98
 
@@ -1,18 +1,26 @@
1
1
  module EnumExt::BasicHelpers
2
2
 
3
+ private
3
4
  # Defines instance method a shortcut for getting integer value of an enum.
4
5
  # for enum named 'status' will generate:
5
6
  #
6
7
  # instance.status_i
7
- private
8
+ #
9
+ # Rem. Will not define helper when enum values are strings, and will print warning
8
10
  def enum_i( enum_name )
11
+ return puts(<<~NOTINTEGER) if columns_hash[enum_name.to_s].type != :integer
12
+ ---------------------NOTINTEGER WARNING!---------------------------
13
+ #{enum_name} is not an integer column, so enum_i helper useless and method will not be defined
14
+ NOTINTEGER
15
+
9
16
  define_method "#{enum_name}_i" do
10
- self.class.send("#{enum_name.to_s.pluralize}")[send(enum_name)].to_i
17
+ self.class.send(enum_name.to_s.pluralize)[send(enum_name)].to_i
11
18
  end
12
19
  end
13
20
 
14
21
  # Defines two scopes for one for an inclusion: `WHERE enum IN( enum1, enum2 )`,
15
22
  # and the second for an exclusion: `WHERE enum NOT IN( enum1, enum2 )`
23
+ # works fine with supersets and basic enums
16
24
  #
17
25
  # Ex:
18
26
  # Request.with_statuses( :payed, :delivery_set ) # >> :payed and [:ready_for_shipment, :on_delivery, :delivered] requests
@@ -20,7 +28,6 @@ module EnumExt::BasicHelpers
20
28
  # Request.without_statuses( :payed, :in_warehouse ) # >> scope all requests with statuses not eq to :payed or :ready_for_shipment
21
29
  def multi_enum_scopes(enum_name)
22
30
  enum_plural = enum_name.to_s.pluralize
23
- enum_obj = send(enum_plural)
24
31
 
25
32
  self.instance_eval do
26
33
  # EnumExt.define_superset_to_enum_method(self, enum_plural)
@@ -28,12 +35,12 @@ module EnumExt::BasicHelpers
28
35
 
29
36
  # with_enums scope
30
37
  scope "with_#{enum_plural}", -> (*enum_list) {
31
- enum_list.blank? ? nil : where( enum_name => enum_obj.superset_to_enum(*enum_list) )
38
+ enum_list.blank? ? nil : where( enum_name => send(enum_plural).superset_to_enum(*enum_list) )
32
39
  } if !respond_to?("with_#{enum_plural}") && respond_to?(:scope)
33
40
 
34
41
  # without_enums scope
35
42
  scope "without_#{enum_plural}", -> (*enum_list) {
36
- enum_list.blank? ? nil : where.not( enum_name => enum_obj.superset_to_enum(*enum_list) )
43
+ enum_list.blank? ? nil : where.not( enum_name => send(enum_plural).superset_to_enum(*enum_list) )
37
44
  } if !respond_to?("without_#{enum_plural}") && respond_to?(:scope)
38
45
  end
39
46
  end
@@ -42,7 +49,7 @@ module EnumExt::BasicHelpers
42
49
  #
43
50
  # Used for mass assigning for collection without callbacks it creates bang methods for collections using update_all.
44
51
  # it's often case when you need bulk update without callbacks, so it's gets frustrating to repeat:
45
- # some_scope.update_all(status: Request.statuses[:new_status], update_at: Time.now)
52
+ # some_scope.update_all(status: :new_status, update_at: Time.now)
46
53
  #
47
54
  # If you need callbacks you can do like this: some_scope.each(&:new_stat!) but if you don't need callbacks
48
55
  # and you have lots of records to change at once you need update_all
@@ -66,11 +73,11 @@ module EnumExt::BasicHelpers
66
73
 
67
74
  def mass_assign_enum( *enums_names )
68
75
  enums_names.each do |enum_name|
69
- enum_vals = self.send( enum_name.to_s.pluralize )
70
-
71
- enum_vals.keys.each do |enum_el|
72
- define_singleton_method( "#{enum_el}!" ) do
73
- self.update_all( {enum_name => enum_vals[enum_el]}.merge( self.column_names.include?('updated_at') ? {updated_at: Time.now} : {} ))
76
+ enum_plural = enum_name.to_s.pluralize
77
+ self.send(enum_plural).keys.each do |label|
78
+ method_name = self.send(enum_plural).transform_enum_label(label)
79
+ define_singleton_method( "#{method_name}!" ) do
80
+ self.update_all( {enum_name => self.send(enum_plural)[label]}.merge( self.column_names.include?('updated_at') ? {updated_at: Time.now} : {} ))
74
81
  end
75
82
  end
76
83
  end
@@ -5,12 +5,12 @@ class EnumExt::EnumWrapper
5
5
  include EnumExt::Annotated
6
6
 
7
7
  # supersets is storing exact definitions, if you need a raw mapping use class.statuses.superset_statuses
8
- attr_reader :enum_values, :supersets, :supersets_raw, :t_options_raw, :localizations, :base_class, :enum_name
8
+ attr_reader :enum_values, :supersets, :supersets_raw, :t_options_raw, :localizations, :base_class, :enum_name, :suffix, :prefix
9
9
 
10
10
  delegate_missing_to :enum_values
11
11
  delegate :inspect, to: :enum_values
12
12
 
13
- def initialize(enum_values, base_class, enum_name)
13
+ def initialize(enum_values, base_class, enum_name, **options)
14
14
  @enum_values = enum_values
15
15
  @supersets = ActiveSupport::HashWithIndifferentAccess.new
16
16
  @supersets_raw = ActiveSupport::HashWithIndifferentAccess.new
@@ -20,6 +20,8 @@ class EnumExt::EnumWrapper
20
20
 
21
21
  @base_class = base_class
22
22
  @enum_name = enum_name
23
+ @suffix = options[:suffix] || options[:_suffix]
24
+ @prefix = options[:prefix] || options[:_prefix]
23
25
  end
24
26
 
25
27
  # ext_sets_to_kinds( :ready_for_shipment, :delivery_set ) -->
@@ -51,6 +53,18 @@ class EnumExt::EnumWrapper
51
53
 
52
54
  alias_method :t, :localizations
53
55
 
56
+ def transform_enum_label(label)
57
+ _prefix = if prefix
58
+ prefix == true ? "#{enum_name}_" : "#{prefix}_"
59
+ end
60
+
61
+ _suffix = if suffix
62
+ suffix == true ? "_#{enum_name}" : "_#{suffix}"
63
+ end
64
+
65
+ "#{_prefix}#{label}#{_suffix}"
66
+ end
67
+
54
68
  private
55
69
 
56
70
  def evaluate_localizations(t_enum_set)
@@ -75,4 +89,6 @@ class EnumExt::EnumWrapper
75
89
  end
76
90
  end
77
91
 
92
+
93
+
78
94
  end
@@ -34,7 +34,7 @@ module EnumExt::HumanizeHelpers
34
34
  # f.select :status, Request.t_statuses_options
35
35
  #
36
36
  # in select in Active Admin filter
37
- # collection: Request.t_statuses_options_i
37
+ # collection: Request.statuses.t_options_i
38
38
  #
39
39
  # Rem: select options breaks when using lambda() with params
40
40
  #
@@ -48,12 +48,11 @@ module EnumExt::HumanizeHelpers
48
48
  enum_name = args.shift
49
49
  localization_definitions = args.pop
50
50
  enum_plural = enum_name.to_s.pluralize
51
- enum_object = send( enum_plural )
52
51
 
53
52
  self.instance_eval do
54
53
  # instance.t_enum
55
54
  define_method "t_#{enum_name}" do
56
- t = block || enum_object.localizations[send(enum_name)]
55
+ t = block || self.class.send(enum_plural).localizations[send(enum_name)]
57
56
  if t.try(:lambda?)
58
57
  t.try(:arity) == 1 && t.call( self ) || t.try(:call)
59
58
  elsif t.is_a?(Proc)
@@ -64,7 +63,7 @@ module EnumExt::HumanizeHelpers
64
63
  end
65
64
 
66
65
  # if localization is absent than block must be given
67
- enum_object.localizations.merge!(
66
+ send(enum_plural).localizations.merge!(
68
67
  localization_definitions.try(:with_indifferent_access) ||
69
68
  send(enum_plural).map do |k, _v|
70
69
  # little bit hackerish: instantiate object just with enum setup and then call its t_.. method which
@@ -110,9 +109,8 @@ module EnumExt::HumanizeHelpers
110
109
  #
111
110
  def self.define_superset_humanization_helpers(base_class, superset_name, enum_name)
112
111
  enum_plural = enum_name.to_s.pluralize
113
- enum_object = base_class.send(enum_plural)
114
112
 
115
- enum_object.define_singleton_method( "t_#{superset_name}_options" ) do
113
+ base_class.send(enum_plural).define_singleton_method( "t_#{superset_name}_options" ) do
116
114
  result = evaluate_localizations(send("t_#{superset_name}"))
117
115
  return result unless result.blank?
118
116
 
@@ -120,7 +118,7 @@ module EnumExt::HumanizeHelpers
120
118
  end
121
119
 
122
120
  # enums.t_options_i
123
- enum_object.define_singleton_method( "t_#{superset_name}_options_i" ) do
121
+ base_class.send(enum_plural).define_singleton_method( "t_#{superset_name}_options_i" ) do
124
122
  result = evaluate_localizations_to_i( send("t_#{superset_name}") )
125
123
  return result unless result.to_h.values.all?(&:blank?)
126
124
 
@@ -129,10 +127,10 @@ module EnumExt::HumanizeHelpers
129
127
 
130
128
 
131
129
  # enums.t_superset ( translations or humanizations subset for a given set )
132
- enum_object.define_singleton_method( "t_#{superset_name}" ) do
130
+ base_class.send(enum_plural).define_singleton_method( "t_#{superset_name}" ) do
133
131
  return [(["Enum translations are missing. Did you forget to translate #{enum_name}"]*2)].to_h if localizations.blank?
134
132
 
135
- enum_object.localizations.slice( *enum_object.send(superset_name) )
133
+ base_class.send(enum_plural).localizations.slice( *base_class.send(enum_plural).send(superset_name) )
136
134
  end
137
135
  end
138
136
  end
@@ -1,69 +1,78 @@
1
1
  module EnumExt::SupersetHelpers
2
2
  # enum_supersets
3
- # This method intend for creating and using some sets of enum values,
4
- # you should
3
+ # **Use-case** whenever you need superset of enums to behave like a super enum.
5
4
  #
6
- # it creates: scopes for subsets,
7
- # instance method with ?
5
+ # You can do this with method **enum_supersets** it creates:
6
+ # - scopes for subsets,
7
+ # - instance methods with `?`
8
8
  #
9
- # For this call:
10
- # enum status: [:in_cart, :waiting_for_payment, :paid, :packing, :ready_for_shipment, :on_delivery, :delivered],
11
- # ext:[ , supersets: {
12
- # delivery_set: [:ready_for_shipment, :on_delivery] # for shipping department for example
13
- # in_warehouse: [:packing, :ready_for_shipment] # this scope is just for superposition example below
14
- # sold: [:payd, :delivery_set, :in_warehouse, :delivered]
15
- # } ]
16
- #Rem:
17
- # enum_supersets can be called twice defining a superposition of already defined supersets
18
- # based on array operations, with already defined array methods ( considering previous example ):
19
- # enum_supersets :status, {
20
- # outside_warehouse: ( delivery_set_statuses - in_warehouse_statuses )... any other array operations like &, + and so can be used
21
- # }
9
+ # For example:
10
+ # enum status: [:in_cart, :waiting_for_payment, :paid, :packing, :ready_for_shipment, :on_delivery, :delivered],
11
+ # ext: [enum_supersets: {
12
+ # around_delivery: [:ready_for_shipment, :on_delivery], # for shipping department for example
13
+ # in_warehouse: [:packing, :ready_for_shipment], # this scope is just for superposition example below
14
+ # sold: [:paid, :around_delivery, :in_warehouse, :delivered] # also you can define any superposition of already defined supersets or enum values
15
+ # }]
22
16
  #
23
- # so the enum_supersets will generate:
24
- # instance:
25
- # methods: delivery_set?, in_warehouse?
26
- # class:
27
- # named scopes: delivery_set, in_warehouse
28
- # class helpers:
29
- # - delivery_set_statuses (=[:ready_for_shipment, :on_delivery, :delivered] ), in_warehouse_statuses
30
- # - delivery_set_statuses_i (= [3,4,5]), in_warehouse_statuses_i (=[3])
31
- # class translation helpers ( started with t_... )
32
- # for select inputs purposes:
33
- # - t_delivery_set_statuses_options (= [['translation or humanization', :ready_for_shipment] ...])
34
- # same as above but with integer as value ( for example to use in Active admin filters )
35
- # - t_delivery_set_statuses_options_i (= [['translation or humanization', 3] ...])
36
-
37
- # Console:
38
- # request.on_delivery!
39
- # request.delivery_set? # >> true
40
-
41
- # Request.delivery_set.exists?(request) # >> true
42
- # Request.in_warehouse.exists?(request) # >> false
17
+ # # supersets will be stored inside enum wrapper object, and can be de-referenced to basic enum values
18
+ # # using wrapper defined methods: "superset_enum_plural", i.e. statuses.sold_statuses -> [:paid, :packing, :ready_for_shipment, :on_delivery, :delivered]
19
+ # # so new supersets could be defined using Array operations against newly defined methods
20
+ # enum_ext :status, enum_supersets: {
21
+ # outside_warehouse: ( statuses.around_delivery - statuses.in_warehouse ) #... any other array operations like &, + and so can be used
22
+ # }
23
+ #
24
+ # it will generate:
25
+ #
26
+ # instance:
27
+ # - methods: around_delivery?, in_warehouse?
28
+ #
29
+ # class:
30
+ # - named scopes: around_delivery, in_warehouse
31
+ #
32
+ # enum methods:
33
+ # - Class.statuses.supersets -- will output superset definition hash
34
+ # - Class.statuses.supersets_raw -- will output superset decompositions to basic enum types hash
43
35
  #
44
- # Request.statuses.supersets[:delivery_set] # >> [:ready_for_shipment, :on_delivery, :delivered]
36
+ # - Class.statuses.around_delivery (=[:ready_for_shipment, :on_delivery, :delivered] ), in_warehouse_statuses
37
+ # - around_delivery_statuses_i (= [3,4,5]), in_warehouse_statuses_i (=[3])
38
+ #
39
+ # translation helpers grouped for superset ( started with t_... ):
40
+ # - Class.statuses.t_around_delivery_options (= [['translation or humanization', :ready_for_shipment] ...] ) for select inputs purposes
41
+ # - Class.statuses.t_around_delivery_options_i (= [['translation or humanization', 3] ...]) same as above but with integer as value ( for example to use in Active admin filters )
42
+ #
43
+ # In console:
44
+ # request.on_delivery!
45
+ # request.around_delivery? # >> true
46
+ #
47
+ # Request.around_delivery.exists?(request) # >> true
48
+ # Request.in_warehouse.exists?(request) # >> false
49
+ #
50
+ # Request.statuses.around_delivery # >> ["ready_for_shipment", "on_delivery", "delivered"]
51
+
45
52
  private
46
53
  def enum_supersets( enum_name, options = {} )
47
54
  enum_plural = enum_name.to_s.pluralize
48
55
 
49
56
  self.instance_eval do
50
- enum_obj = send(enum_plural)
51
- enum_obj.supersets.merge!( options.transform_values{ _1.try(:map, &:to_s) || _1.to_s } )
57
+ suffix = send(enum_plural).suffix
58
+ prefix = send(enum_plural).prefix
59
+ send(enum_plural).supersets.merge!( options.transform_values{ _1.try(:map, &:to_s) || _1.to_s } )
52
60
 
53
61
  options.each do |superset_name, enum_vals|
54
- raise "Can't define superset with name: #{superset_name}, #{enum_plural} already has such method!" if enum_obj.respond_to?(superset_name)
62
+ raise "Can't define superset with name: #{superset_name}, #{enum_plural} already has such method!" if send(enum_plural).respond_to?(superset_name)
55
63
 
56
- enum_obj.supersets_raw[superset_name] = enum_obj.superset_to_enum(*enum_vals)
64
+ send(enum_plural).supersets_raw[superset_name] = send(enum_plural).superset_to_enum(*enum_vals)
57
65
 
58
- # class.statuses.superset_statuses
59
- enum_obj.define_singleton_method(superset_name) { enum_obj.superset_to_enum(*enum_vals) }
66
+ # class.enum_wrapper.superset
67
+ send(enum_plural).define_singleton_method(superset_name) { base_class.send(enum_plural).superset_to_enum(*enum_vals) }
60
68
 
69
+ superset_method_name = send(enum_plural).transform_enum_label(superset_name)
61
70
  # superset_name scope
62
- scope superset_name, -> { where( enum_name => enum_obj.send(superset_name) ) } if respond_to?(:scope)
71
+ scope superset_method_name, -> { where( enum_name => send(enum_plural).send(superset_name) ) } if respond_to?(:scope)
63
72
 
64
73
  # instance.superset_name?
65
- define_method "#{superset_name}?" do
66
- send(enum_name) && enum_obj.send(superset_name).include?( send(enum_name) )
74
+ define_method "#{superset_method_name}?" do
75
+ send(enum_name) && self.class.send(enum_plural).send(superset_name).include?( send(enum_name) )
67
76
  end
68
77
 
69
78
  EnumExt::HumanizeHelpers.define_superset_humanization_helpers( self, superset_name, enum_name )
@@ -1,3 +1,3 @@
1
1
  module EnumExt
2
- VERSION = "0.8.0"
2
+ VERSION = "0.9.0"
3
3
  end
data/lib/enum_ext.rb CHANGED
@@ -49,33 +49,38 @@ module EnumExt
49
49
  def enum(name = nil, values = nil, **options)
50
50
  single_enum_definition = name.present?
51
51
  extensions = options.delete(:ext)
52
+ options_dup = options.dup
52
53
 
53
54
  (ActiveRecord::VERSION::MAJOR >= 7 ? super : super(options)).tap do |multiple_enum_definitions|
54
55
  if single_enum_definition
55
- enum_ext(name, extensions)
56
+ replace_enum_with_wrapper(name, options_dup)
57
+ enum_ext(name, [*extensions])
56
58
  else
57
- multiple_enum_definitions.each { |enum_name,| enum_ext(enum_name, extensions) }
59
+ multiple_enum_definitions.each { |enum_name,|
60
+ replace_enum_with_wrapper(enum_name, options_dup)
61
+ enum_ext(enum_name, [*extensions])
62
+ }
58
63
  end
59
64
  end
60
65
  end
61
66
 
62
67
  # its an extension helper, on the opposite to basic enum method could be called multiple times
63
68
  def enum_ext(enum_name, extensions)
64
- replace_enum_with_wrapper(enum_name)
65
- # [:enum_i, :enum_multi_scopes, enum_supersets: { valid: [:fresh, :cool], invalid: [:stale] }]
69
+ # [:enum_i, :enum_multi_scopes, enum_supersets: { valid: [:fresh, :cool], invalid: [:stale] }]
66
70
  # --> [:enum_i, :enum_multi_scopes, [:enum_supersets, { valid: [:fresh, :cool], invalid: [:stale] }]
67
71
  [*extensions].map { _1.try(:to_a)&.flatten || _1 }
68
72
  .each { |(ext_method, params)| send(*[ext_method, enum_name, params].compact) }
69
73
  end
70
74
 
71
75
  private
72
- def replace_enum_with_wrapper(enum_name)
76
+
77
+ def replace_enum_with_wrapper(enum_name, options_dup)
73
78
  enum_name_plural = enum_name.to_s.pluralize
74
79
  return if send(enum_name_plural).is_a?(EnumWrapper)
75
80
 
76
81
  # enum will freeze values so there is no other way to move extended functionality,
77
82
  # than to use wrapper and delegate everything to enum_values
78
- enum_wrapper = EnumWrapper.new(send(enum_name_plural), self, enum_name)
83
+ enum_wrapper = EnumWrapper.new(send(enum_name_plural), self, enum_name, **options_dup)
79
84
  # "self" here is a base enum class, so we are replacing original enum definition, with a wrapper
80
85
  define_singleton_method(enum_name_plural) { enum_wrapper }
81
86
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enum_ext
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - alekseyl
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-10-02 00:00:00.000000000 Z
11
+ date: 2023-11-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord