enum_ext 0.1.8 → 0.4.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.
- checksums.yaml +5 -5
- data/.travis.yml +6 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +68 -23
- data/README.md +152 -141
- data/Rakefile +8 -1
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/enum_ext.gemspec +9 -5
- data/lib/enum_ext.rb +232 -147
- data/lib/enum_ext/version.rb +1 -1
- metadata +76 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 2fb6aee80ce2daab446b5670b4e241cdf7c3628696be8c391280eda35c5370bf
|
|
4
|
+
data.tar.gz: dfc6d38cfe49d9335e167f02b8a9af72d825f74913302a7dec028faea6af9836
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c46755afcf16127058c21af572d54845c7c4dc8c87190ef086d1a2df80af3a74f249704fdf9939ac90316dc7019cb8198864d20f10a5a91dddcbc124a70462f0
|
|
7
|
+
data.tar.gz: cadb8ecb8fa5ea4a6be810ce8579dfd200bbc680e69c75f860a986bccadf9e66b8f9fdef10c5c3dff28c6cc7559d0e2b485fddc1316bc335c9153f5be5b68736
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile.lock
CHANGED
|
@@ -1,42 +1,87 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
enum_ext (0.1
|
|
5
|
-
activerecord (>= 4.
|
|
4
|
+
enum_ext (0.4.1)
|
|
5
|
+
activerecord (>= 5.2.4.3)
|
|
6
6
|
|
|
7
7
|
GEM
|
|
8
8
|
remote: https://rubygems.org/
|
|
9
9
|
specs:
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
actionpack (6.0.3.4)
|
|
11
|
+
actionview (= 6.0.3.4)
|
|
12
|
+
activesupport (= 6.0.3.4)
|
|
13
|
+
rack (~> 2.0, >= 2.0.8)
|
|
14
|
+
rack-test (>= 0.6.3)
|
|
15
|
+
rails-dom-testing (~> 2.0)
|
|
16
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
|
17
|
+
actionview (6.0.3.4)
|
|
18
|
+
activesupport (= 6.0.3.4)
|
|
12
19
|
builder (~> 3.1)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
erubi (~> 1.4)
|
|
21
|
+
rails-dom-testing (~> 2.0)
|
|
22
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
|
23
|
+
activemodel (6.0.3.4)
|
|
24
|
+
activesupport (= 6.0.3.4)
|
|
25
|
+
activerecord (6.0.3.4)
|
|
26
|
+
activemodel (= 6.0.3.4)
|
|
27
|
+
activesupport (= 6.0.3.4)
|
|
28
|
+
activesupport (6.0.3.4)
|
|
29
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
30
|
+
i18n (>= 0.7, < 2)
|
|
20
31
|
minitest (~> 5.1)
|
|
21
|
-
thread_safe (~> 0.3, >= 0.3.4)
|
|
22
32
|
tzinfo (~> 1.1)
|
|
23
|
-
|
|
24
|
-
builder (3.2.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
zeitwerk (~> 2.2, >= 2.2.2)
|
|
34
|
+
builder (3.2.4)
|
|
35
|
+
byebug (11.1.3)
|
|
36
|
+
concurrent-ruby (1.1.7)
|
|
37
|
+
crass (1.0.6)
|
|
38
|
+
erubi (1.10.0)
|
|
39
|
+
i18n (1.8.5)
|
|
40
|
+
concurrent-ruby (~> 1.0)
|
|
41
|
+
loofah (2.8.0)
|
|
42
|
+
crass (~> 1.0.2)
|
|
43
|
+
nokogiri (>= 1.5.9)
|
|
44
|
+
method_source (1.0.0)
|
|
45
|
+
mini_portile2 (2.4.0)
|
|
46
|
+
minitest (5.14.2)
|
|
47
|
+
nokogiri (1.10.10)
|
|
48
|
+
mini_portile2 (~> 2.4.0)
|
|
49
|
+
rack (2.2.3)
|
|
50
|
+
rack-test (1.1.0)
|
|
51
|
+
rack (>= 1.0, < 3)
|
|
52
|
+
rails-dom-testing (2.0.3)
|
|
53
|
+
activesupport (>= 4.2.0)
|
|
54
|
+
nokogiri (>= 1.6)
|
|
55
|
+
rails-html-sanitizer (1.3.0)
|
|
56
|
+
loofah (~> 2.3)
|
|
57
|
+
rails-i18n (6.0.0)
|
|
58
|
+
i18n (>= 0.7, < 2)
|
|
59
|
+
railties (>= 6.0.0, < 7)
|
|
60
|
+
railties (6.0.3.4)
|
|
61
|
+
actionpack (= 6.0.3.4)
|
|
62
|
+
activesupport (= 6.0.3.4)
|
|
63
|
+
method_source
|
|
64
|
+
rake (>= 0.8.7)
|
|
65
|
+
thor (>= 0.20.3, < 2.0)
|
|
66
|
+
rake (13.0.1)
|
|
67
|
+
sqlite3 (1.4.2)
|
|
68
|
+
thor (1.0.1)
|
|
69
|
+
thread_safe (0.3.6)
|
|
70
|
+
tzinfo (1.2.8)
|
|
31
71
|
thread_safe (~> 0.1)
|
|
72
|
+
zeitwerk (2.4.2)
|
|
32
73
|
|
|
33
74
|
PLATFORMS
|
|
34
75
|
ruby
|
|
35
76
|
|
|
36
77
|
DEPENDENCIES
|
|
37
|
-
bundler (
|
|
78
|
+
bundler (>= 1.11)
|
|
79
|
+
byebug
|
|
38
80
|
enum_ext!
|
|
39
|
-
|
|
81
|
+
minitest
|
|
82
|
+
rails-i18n (>= 4)
|
|
83
|
+
rake (>= 10.0)
|
|
84
|
+
sqlite3
|
|
40
85
|
|
|
41
86
|
BUNDLED WITH
|
|
42
|
-
1.
|
|
87
|
+
2.1.4
|
data/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# EnumExt
|
|
2
2
|
|
|
3
|
-
EnumExt extends rails enum
|
|
3
|
+
EnumExt extends rails enum with localization/translation and it's helpers, mass-assign on scopes with bang, advanced sets logic over existing enum.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
Add this line to your application's Gemfile:
|
|
8
8
|
|
|
9
9
|
```ruby
|
|
10
|
-
gem 'enum_ext'
|
|
10
|
+
gem 'enum_ext', '~> 0.3'
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
And then execute:
|
|
@@ -19,22 +19,26 @@ Or install it yourself as:
|
|
|
19
19
|
$ gem install enum_ext
|
|
20
20
|
|
|
21
21
|
## Usage
|
|
22
|
-
To use enum extension extend main model class with EnumExt module,
|
|
22
|
+
To use enum extension extend main model class with EnumExt module,
|
|
23
|
+
and customize your enums the way you need:
|
|
23
24
|
|
|
24
25
|
class SomeModel
|
|
25
26
|
extend EnumExt
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
enum_i ...
|
|
29
|
+
humanize_enum ...
|
|
30
|
+
translate_enum ...
|
|
28
31
|
ext_enum_sets ...
|
|
29
32
|
mass_assign_enum ...
|
|
30
33
|
end
|
|
31
34
|
|
|
32
|
-
Let's assume that we have model Request representing some buying requests with enum **status**, and we have model Order with requests,
|
|
35
|
+
Let's assume that we have model Request representing some buying requests with enum **status**, and we have model Order with requests,
|
|
36
|
+
representing single purchase, like this:
|
|
33
37
|
|
|
34
38
|
class Request
|
|
35
39
|
extend EnumExt
|
|
36
40
|
belongs_to :order
|
|
37
|
-
enum status: [ :in_cart, :waiting_for_payment, :
|
|
41
|
+
enum status: [ :in_cart, :waiting_for_payment, :paid, :ready_for_shipment, :on_delivery, :delivered ]
|
|
38
42
|
end
|
|
39
43
|
|
|
40
44
|
class Order
|
|
@@ -43,48 +47,77 @@ Or install it yourself as:
|
|
|
43
47
|
|
|
44
48
|
Now let's review some examples of possible enum extensions
|
|
45
49
|
|
|
46
|
-
###
|
|
50
|
+
### Humanization (humanize_enum)
|
|
47
51
|
|
|
48
|
-
|
|
49
|
-
...
|
|
50
|
-
localize_enum :status, {
|
|
51
|
-
|
|
52
|
-
#locale dependent example ( it dynamically use current locale ):
|
|
53
|
-
in_cart: -> { I18n.t("request.status.in_cart") },
|
|
54
|
-
|
|
55
|
-
#locale dependent example with internal pluralization and lambda:
|
|
56
|
-
payed: -> (t_self) { I18n.t("request.status.payed", count: t_self.sum ) }
|
|
57
|
-
|
|
58
|
-
#locale dependent example with internal pluralization and proc:
|
|
59
|
-
payed: proc { I18n.t("request.status.payed", count: sum ) }
|
|
60
|
-
|
|
61
|
-
#locale independent:
|
|
62
|
-
ready_for_shipment: "Ready to go!"
|
|
63
|
-
}
|
|
64
|
-
end
|
|
52
|
+
if app doesn't need internationalization, it may use humanize_enum to make enum user friendly
|
|
65
53
|
|
|
66
|
-
|
|
54
|
+
```
|
|
55
|
+
humanize_enum :status, {
|
|
56
|
+
#locale dependent example with pluralization and lambda:
|
|
57
|
+
in_cart: -> (t_self) { I18n.t("request.status.in_cart", count: t_self.sum ) }
|
|
58
|
+
|
|
59
|
+
#locale dependent example with pluralization and proc:
|
|
60
|
+
paid: Proc.new{ I18n.t("request.status.paid", count: self.sum ) }
|
|
61
|
+
|
|
62
|
+
#locale independent:
|
|
63
|
+
ready_for_shipment: "Ready to go!"
|
|
64
|
+
}
|
|
65
|
+
end
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
This humanize_enum adds to instance:
|
|
69
|
+
- t_in_cart, t_paid, t_ready_for_shipment
|
|
70
|
+
|
|
71
|
+
and to class:
|
|
72
|
+
- t_statuses - as given or generated values
|
|
73
|
+
- t_statuses_options - translated enum values options for select input
|
|
74
|
+
- t_statuses_options_i - same as above but use int values with translations works for ActiveAdmin filters for instance
|
|
67
75
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
request.status # >> payed
|
|
71
|
-
request.t_status # >> "Payed 3 dollars"
|
|
72
|
-
Request.t_statuses # >> { in_cart: -> { I18n.t("request.status.in_cart") }, .... }
|
|
76
|
+
|
|
77
|
+
Example with block:
|
|
73
78
|
|
|
74
|
-
|
|
79
|
+
```
|
|
80
|
+
humanize_enum :status do
|
|
81
|
+
I18n.t("scope.#{status}")
|
|
82
|
+
end
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Example for select:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
f.select :status, Request.t_statuses_options
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
in Active Admin filters
|
|
92
|
+
```
|
|
93
|
+
filter :status, as: :select, label: 'Status', collection: Request.t_statuses_options_i
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
Rem: select options may break when using lambda() or proc with instance method, but will survive with block
|
|
98
|
+
|
|
99
|
+
Console:
|
|
100
|
+
```
|
|
101
|
+
request.sum = 3
|
|
102
|
+
request.paid!
|
|
103
|
+
request.status # >> paid
|
|
104
|
+
request.t_status # >> "paid 3 dollars"
|
|
105
|
+
Request.t_statuses # >> { in_cart: -> { I18n.t("request.status.in_cart") }, .... }
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Could be called multiple times, all humanization definitions will be merged under the hood.
|
|
109
|
+
|
|
110
|
+
### Translate (translate_enum)
|
|
75
111
|
|
|
76
|
-
|
|
77
|
-
..
|
|
78
|
-
delivered: "Delivered at: %{date}"
|
|
79
|
-
}
|
|
80
|
-
request.delivered!
|
|
81
|
-
request.t_status % {date: Time.now.to_s} >> Delivered at: 05.02.2016
|
|
112
|
+
Enum is translated using scope 'active_record.attributes.class_name_underscore.enum_plural', or the given one:
|
|
82
113
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
f.select :status, Request.t_statuses.invert.to_a
|
|
114
|
+
translate_enum :status, 'active_record.request.enum'
|
|
86
115
|
|
|
87
|
-
|
|
116
|
+
Or it can be done with block either with translate or humanize:
|
|
117
|
+
|
|
118
|
+
translate_enum :status do
|
|
119
|
+
I18n.t( "active_record.request.enum.#{status}" )
|
|
120
|
+
end
|
|
88
121
|
|
|
89
122
|
### Enum to_i shortcut ( enum_i )
|
|
90
123
|
|
|
@@ -93,124 +126,99 @@ Defines method enum_name_i shortcut for Model.enum_names[elem.enum_name]
|
|
|
93
126
|
**Ex**
|
|
94
127
|
enum_i :status
|
|
95
128
|
...
|
|
96
|
-
request.
|
|
129
|
+
request.paid_i # 10
|
|
97
130
|
|
|
98
131
|
|
|
99
|
-
|
|
100
132
|
### Enum Sets (ext_enum_sets)
|
|
101
133
|
|
|
102
|
-
**Use-case** For example you have pay bills of different types, and you want to group some types in debit and credit "super-types",
|
|
103
|
-
|
|
104
|
-
You can do this with method **ext_enum_sets**, it creates: scopes for subsets like enum did, instance method with ? similar to enum methods, and so...
|
|
134
|
+
**Use-case** For example you have pay bills of different types, and you want to group some types in debit and credit "super-types",
|
|
135
|
+
and have scope PayBill.debit, instance method with question mark as usual enum does pay_bill.debit?.
|
|
105
136
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
Request.non_payed_statuses # >> [:in_cart, :waiting_for_payment]
|
|
132
|
-
|
|
133
|
-
Request.with_statuses( :payed, :in_cart ) # >> scope for all in_cart and payed requests
|
|
134
|
-
Request.without_statuses( :payed ) # >> scope for all requests with statuses not eq to payed
|
|
135
|
-
Request.without_statuses( :payed, :non_payed ) # >> scope all requests with statuses not eq to payed and in_cart + waiting_for_payment
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
#### Rem:
|
|
139
|
-
|
|
140
|
-
You can call ext_enum_sets more than one time defining a superposition of already defined sets:
|
|
141
|
-
|
|
142
|
-
class Request
|
|
143
|
-
...
|
|
144
|
-
ext_enum_sets (... first time you call ext_enum_sets )
|
|
145
|
-
ext_enum_sets :status, {
|
|
146
|
-
already_payed: ( [:payed] | delivery_set_statuses ),
|
|
147
|
-
outside_wharehouse: ( delivery_set_statuses - in_warehouse_statuses )... # any other array operations like &, + and so can be used
|
|
148
|
-
}
|
|
137
|
+
You can do this with method **ext_enum_sets** it creates: scopes for subsets, instance method with ? and some class methods helpers
|
|
138
|
+
|
|
139
|
+
For this call:
|
|
140
|
+
```
|
|
141
|
+
ext_enum_sets :status, {
|
|
142
|
+
delivery_set: [:ready_for_shipment, :on_delivery, :delivered] # for shipping department for example
|
|
143
|
+
in_warehouse: [:ready_for_shipment] # this just for superposition example below
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
it will generate:
|
|
147
|
+
```
|
|
148
|
+
instance:
|
|
149
|
+
- methods: delivery_set?, in_warehouse?
|
|
150
|
+
|
|
151
|
+
class:
|
|
152
|
+
- named scopes: delivery_set, in_warehouse
|
|
153
|
+
- parametrized scopes: with_statuses, without_statuses
|
|
154
|
+
class helpers:
|
|
155
|
+
- delivery_set_statuses (=[:ready_for_shipment, :on_delivery, :delivered] ), in_warehouse_statuses
|
|
156
|
+
- delivery_set_statuses_i (= [3,4,5]), in_warehouse_statuses_i (=[3])
|
|
157
|
+
|
|
158
|
+
class translation helpers ( started with t_... ):
|
|
159
|
+
- t_delivery_set_statuses_options (= [['translation or humanization', :ready_for_shipment] ...] ) for select inputs purposes
|
|
160
|
+
- t_delivery_set_statuses_options_i (= [['translation or humanization', 3] ...]) same as above but with integer as value ( for example to use in Active admin filters )
|
|
161
|
+
```
|
|
149
162
|
|
|
150
|
-
|
|
163
|
+
```
|
|
164
|
+
Console:
|
|
165
|
+
request.on_delivery!
|
|
166
|
+
request.delivery_set? # >> true
|
|
151
167
|
|
|
152
|
-
|
|
168
|
+
Request.delivery_set.exists?(request) # >> true
|
|
169
|
+
Request.in_warehouse.exists?(request) # >> false
|
|
170
|
+
|
|
171
|
+
Request.delivery_set_statuses # >> [:ready_for_shipment, :on_delivery, :delivered]
|
|
172
|
+
|
|
173
|
+
Request.with_statuses( :payed, :delivery_set ) # >> :payed and [:ready_for_shipment, :on_delivery, :delivered] requests
|
|
174
|
+
Request.without_statuses( :payed ) # >> scope for all requests with statuses not eq to :payed
|
|
175
|
+
Request.without_statuses( :payed, :in_warehouse ) # >> scope all requests with statuses not eq to :payed or :ready_for_shipment
|
|
176
|
+
```
|
|
153
177
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
178
|
+
Rem:
|
|
179
|
+
ext_enum_sets can be called twice defining a superposition of already defined sets ( considering previous example ):
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
ext_enum_sets :status, {
|
|
183
|
+
outside_wharehouse: ( delivery_set_statuses - in_warehouse_statuses )... any other array operations like &, + and so can be used
|
|
184
|
+
}
|
|
185
|
+
```
|
|
161
186
|
|
|
162
|
-
Console:
|
|
163
187
|
|
|
164
|
-
|
|
165
|
-
request2.waiting_for_payment!
|
|
166
|
-
Request.non_payed.payed!
|
|
167
|
-
request1.payed? # >> true
|
|
168
|
-
request2.payed? # >> true
|
|
169
|
-
request1.updated_at # >> ~ Time.now
|
|
170
|
-
defined?(Request::MassAssignEnum) # >> true
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
order.requests.already_payed.count # >> N
|
|
174
|
-
order.requests.delivered.count # >> M
|
|
175
|
-
order.requests.already_payed.delivered!
|
|
176
|
-
order.requests.already_payed.count # >> 0
|
|
177
|
-
order.requests.delivered.count # >> N + M
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
####Rem:
|
|
181
|
-
|
|
182
|
-
**mass_assign_enum** accepts additional options as last argument. Calling
|
|
188
|
+
### Mass-assign ( mass_assign_enum )
|
|
183
189
|
|
|
184
|
-
|
|
190
|
+
Syntax sugar for mass-assigning enum values.
|
|
185
191
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
192
|
+
**Use-case:** it's often case when I need bulk update without callbacks, so it's gets frustrating to repeat:
|
|
193
|
+
```
|
|
194
|
+
some_scope.update_all(status: Request.statuses[:new_status], update_at: Time.now)
|
|
195
|
+
```
|
|
196
|
+
If you need callbacks you can do like this: some_scope.each(&:new_stat!) but if you don't need callbacks and you
|
|
197
|
+
have hundreds and thousands of records to change at once you need update_all
|
|
191
198
|
|
|
192
|
-
|
|
199
|
+
```
|
|
200
|
+
mass_assign_enum( :status )
|
|
201
|
+
```
|
|
193
202
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
**but it wouldn't work without 'scope' part!** If you want to use it without 'scope' you may do it this way:
|
|
197
|
-
|
|
198
|
-
class Request
|
|
199
|
-
...
|
|
200
|
-
mass_assign_enum( :status, relation: true, association_relation: false )
|
|
201
|
-
end
|
|
203
|
+
Console:
|
|
202
204
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
205
|
+
```
|
|
206
|
+
request1.in_cart!
|
|
207
|
+
request2.waiting_for_payment!
|
|
208
|
+
Request.non_paid.paid!
|
|
209
|
+
request1.paid? # >> true
|
|
210
|
+
request2.paid? # >> true
|
|
211
|
+
request1.updated_at # >> ~ Time.now
|
|
206
212
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
213
|
+
order.requests.already_paid.count # >> N
|
|
214
|
+
order.requests.delivered.count # >> M
|
|
215
|
+
order.requests.already_paid.delivered!
|
|
216
|
+
order.requests.already_paid.count # >> 0
|
|
217
|
+
order.requests.delivered.count # >> N + M
|
|
218
|
+
```
|
|
211
219
|
|
|
212
220
|
## Tests
|
|
213
|
-
|
|
221
|
+
rake test
|
|
214
222
|
|
|
215
223
|
## Development
|
|
216
224
|
|
|
@@ -224,3 +232,6 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/alekse
|
|
|
224
232
|
|
|
225
233
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
|
226
234
|
|
|
235
|
+
### Thanks
|
|
236
|
+
|
|
237
|
+
Thanks for the star vzamanillo, it inspires me to do mass refactor and gracefully cover code in this gem by tests.
|
data/Rakefile
CHANGED
data/bin/console
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "enum_ext"
|
|
5
|
+
|
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
8
|
+
|
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
+
# require "pry"
|
|
11
|
+
# Pry.start
|
|
12
|
+
|
|
13
|
+
require "irb"
|
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/enum_ext.gemspec
CHANGED
|
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
|
|
|
9
9
|
spec.authors = ["alekseyl"]
|
|
10
10
|
spec.email = ["leshchuk@gmail.com"]
|
|
11
11
|
|
|
12
|
-
spec.summary = %q{Enum extension, ads enum sets, mass-assign
|
|
13
|
-
spec.description = %q{Enum extension, ads enum sets, mass-assign
|
|
12
|
+
spec.summary = %q{Enum extension, ads enum sets, mass-assign, localization, and some sugar helpers.}
|
|
13
|
+
spec.description = %q{Enum extension, ads enum sets, mass-assign, localization, and some sugar helpers.}
|
|
14
14
|
spec.homepage = "https://github.com/alekseyl/enum_ext"
|
|
15
15
|
spec.license = "MIT"
|
|
16
16
|
|
|
@@ -19,8 +19,12 @@ Gem::Specification.new do |spec|
|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
20
20
|
spec.require_paths = ["lib"]
|
|
21
21
|
|
|
22
|
-
spec.add_dependency
|
|
22
|
+
spec.add_dependency 'activerecord', ">= 5.2.4.3"
|
|
23
23
|
|
|
24
|
-
spec.add_development_dependency
|
|
25
|
-
spec.add_development_dependency
|
|
24
|
+
spec.add_development_dependency 'minitest'
|
|
25
|
+
spec.add_development_dependency 'bundler', '>= 1.11'
|
|
26
|
+
spec.add_development_dependency 'rake', '>= 10.0'
|
|
27
|
+
spec.add_development_dependency 'rails-i18n', '>=4'
|
|
28
|
+
spec.add_development_dependency 'sqlite3'
|
|
29
|
+
spec.add_development_dependency 'byebug'
|
|
26
30
|
end
|
data/lib/enum_ext.rb
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
require
|
|
1
|
+
require 'enum_ext/version'
|
|
2
2
|
|
|
3
3
|
# Let's assume we have model Request with enum status, and we have model Order with requests like this:
|
|
4
4
|
# class Request
|
|
5
5
|
# extend EnumExt
|
|
6
6
|
# belongs_to :order
|
|
7
|
-
# enum status:
|
|
7
|
+
# enum status: { in_cart: 0, waiting_for_payment: 1, payed: 2, ready_for_shipment: 3, on_delivery: 4, delivered: 5 }
|
|
8
8
|
# end
|
|
9
9
|
#
|
|
10
10
|
# class Order
|
|
@@ -12,211 +12,296 @@ require "enum_ext/version"
|
|
|
12
12
|
# end
|
|
13
13
|
#
|
|
14
14
|
module EnumExt
|
|
15
|
-
# Ex using localize_enum with Request
|
|
16
|
-
# class Request
|
|
17
|
-
# ...
|
|
18
|
-
# localize_enum :status, {
|
|
19
|
-
#
|
|
20
|
-
# #locale dependent example ( it dynamically use current locale ):
|
|
21
|
-
# in_cart: -> { I18n.t("request.status.in_cart") },
|
|
22
|
-
|
|
23
|
-
# #locale dependent example with pluralization and lambda:
|
|
24
|
-
# payed: -> (t_self) { I18n.t("request.status.payed", count: t_self.sum ) }
|
|
25
|
-
|
|
26
|
-
# #locale dependent example with pluralization and proc:
|
|
27
|
-
# payed: proc{ I18n.t("request.status.payed", count: self.sum ) }
|
|
28
|
-
#
|
|
29
|
-
# #locale independent:
|
|
30
|
-
# ready_for_shipment: "Ready to go!"
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
# }
|
|
34
|
-
# end
|
|
35
|
-
|
|
36
|
-
# Console:
|
|
37
|
-
# request.sum = 3
|
|
38
|
-
# request.payed!
|
|
39
|
-
# request.status # >> payed
|
|
40
|
-
# request.t_status # >> "Payed 3 dollars"
|
|
41
|
-
# Request.t_statuses # >> { in_cart: -> { I18n.t("request.status.in_cart") }, .... }
|
|
42
|
-
|
|
43
|
-
# if you need some substitution you can go like this
|
|
44
|
-
# localize_enum :status, {
|
|
45
|
-
# ..
|
|
46
|
-
# delivered: "Delivered at: %{date}"
|
|
47
|
-
# }
|
|
48
|
-
# request.delivered!
|
|
49
|
-
# request.t_status % {date: Time.now.to_s} # >> Delivered at: 05.02.2016
|
|
50
|
-
#
|
|
51
|
-
# Using in select:
|
|
52
|
-
# f.select :status, Request.t_statuses.invert.to_a
|
|
53
|
-
#
|
|
54
|
-
def localize_enum( enum_name, localizations )
|
|
55
|
-
self.instance_eval do
|
|
56
|
-
define_singleton_method( "t_#{enum_name.to_s.pluralize}" ) do
|
|
57
|
-
localizations.try(:with_indifferent_access) || localizations
|
|
58
|
-
end
|
|
59
|
-
define_method "t_#{enum_name}" do
|
|
60
|
-
t = localizations.try(:with_indifferent_access)[send(enum_name)]
|
|
61
|
-
if t.try(:lambda?)
|
|
62
|
-
t.try(:arity) == 1 && t.call( self ) || t.try(:call)
|
|
63
|
-
elsif t.is_a?(Proc)
|
|
64
|
-
instance_eval(&t)
|
|
65
|
-
else
|
|
66
|
-
t
|
|
67
|
-
end.to_s
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
15
|
|
|
16
|
+
# defines shortcut for getting integer value of enum.
|
|
17
|
+
# for enum named 'status' will generate:
|
|
18
|
+
# instance.status_i
|
|
72
19
|
def enum_i( enum_name )
|
|
73
20
|
define_method "#{enum_name}_i" do
|
|
74
21
|
self.class.send("#{enum_name.to_s.pluralize}")[send(enum_name)].to_i
|
|
75
22
|
end
|
|
76
23
|
end
|
|
77
24
|
|
|
78
|
-
|
|
79
|
-
#
|
|
80
|
-
#
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
# #class scopes: with_statuses, without_statuses
|
|
87
|
-
# #class non_payed_statuses, delivery_set_statuses ( = [:in_cart, :waiting_for_payment], [:ready_for_shipment, :on_delivery, :delivered].. )
|
|
25
|
+
|
|
26
|
+
# ext_enum_sets
|
|
27
|
+
# This method intend for creating and using some sets of enum values
|
|
28
|
+
# it creates: scopes for subsets,
|
|
29
|
+
# instance method with ?,
|
|
30
|
+
# and some class methods helpers
|
|
31
|
+
#
|
|
32
|
+
# For this call:
|
|
88
33
|
# ext_enum_sets :status, {
|
|
89
|
-
# non_payed: [:in_cart, :waiting_for_payment],
|
|
90
34
|
# delivery_set: [:ready_for_shipment, :on_delivery, :delivered] # for shipping department for example
|
|
91
|
-
# in_warehouse: [:ready_for_shipment]
|
|
35
|
+
# in_warehouse: [:ready_for_shipment] # this scope is just for superposition example below
|
|
92
36
|
# }
|
|
93
|
-
#
|
|
37
|
+
#
|
|
38
|
+
# it will generate:
|
|
39
|
+
# instance:
|
|
40
|
+
# methods: delivery_set?, in_warehouse?
|
|
41
|
+
# class:
|
|
42
|
+
# named scopes: delivery_set, in_warehouse
|
|
43
|
+
# parametrized scopes: with_statuses, without_statuses
|
|
44
|
+
# class helpers:
|
|
45
|
+
# - delivery_set_statuses (=[:ready_for_shipment, :on_delivery, :delivered] ), in_warehouse_statuses
|
|
46
|
+
# - delivery_set_statuses_i (= [3,4,5]), in_warehouse_statuses_i (=[3])
|
|
47
|
+
# class translation helpers ( started with t_... )
|
|
48
|
+
# for select inputs purposes:
|
|
49
|
+
# - t_delivery_set_statuses_options (= [['translation or humanization', :ready_for_shipment] ...])
|
|
50
|
+
# same as above but with integer as value ( for example to use in Active admin filters )
|
|
51
|
+
# - t_delivery_set_statuses_options_i (= [['translation or humanization', 3] ...])
|
|
94
52
|
|
|
95
53
|
# Console:
|
|
96
|
-
# request.
|
|
97
|
-
# request.
|
|
54
|
+
# request.on_delivery!
|
|
55
|
+
# request.delivery_set? # >> true
|
|
98
56
|
|
|
99
|
-
# Request.
|
|
100
|
-
# Request.
|
|
101
|
-
|
|
102
|
-
# Request.
|
|
57
|
+
# Request.delivery_set.exists?(request) # >> true
|
|
58
|
+
# Request.in_warehouse.exists?(request) # >> false
|
|
59
|
+
#
|
|
60
|
+
# Request.delivery_set_statuses # >> [:ready_for_shipment, :on_delivery, :delivered]
|
|
103
61
|
#
|
|
104
|
-
# Request.with_statuses( :payed, :
|
|
105
|
-
# Request.without_statuses( :payed )
|
|
106
|
-
# Request.without_statuses( :payed, :
|
|
62
|
+
# Request.with_statuses( :payed, :delivery_set ) # >> :payed and [:ready_for_shipment, :on_delivery, :delivered] requests
|
|
63
|
+
# Request.without_statuses( :payed ) # >> scope for all requests with statuses not eq to :payed
|
|
64
|
+
# Request.without_statuses( :payed, :in_warehouse ) # >> scope all requests with statuses not eq to :payed or :ready_for_shipment
|
|
107
65
|
#
|
|
108
66
|
|
|
109
67
|
#Rem:
|
|
110
|
-
# ext_enum_sets can be called twice defining a
|
|
111
|
-
#
|
|
112
|
-
#
|
|
113
|
-
#
|
|
114
|
-
# ext_enum_sets :status, {
|
|
115
|
-
# already_payed: ( [:payed] | delivery_set_statuses ),
|
|
116
|
-
# outside_wharehouse: ( delivery_set_statuses - in_warehouse_statuses )... any other array operations like &, + and so can be used
|
|
117
|
-
# }
|
|
68
|
+
# ext_enum_sets can be called twice defining a superposition of already defined sets ( considering previous example ):
|
|
69
|
+
# ext_enum_sets :status, {
|
|
70
|
+
# outside_wharehouse: ( delivery_set_statuses - in_warehouse_statuses )... any other array operations like &, + and so can be used
|
|
71
|
+
# }
|
|
118
72
|
def ext_enum_sets( enum_name, options )
|
|
73
|
+
enum_plural = enum_name.to_s.pluralize
|
|
74
|
+
|
|
119
75
|
self.instance_eval do
|
|
120
76
|
options.each do |set_name, enum_vals|
|
|
121
|
-
|
|
77
|
+
# set_name scope
|
|
78
|
+
scope set_name, -> { where( enum_name => self.send( enum_plural ).slice( *enum_vals.map(&:to_s) ).values ) }
|
|
79
|
+
|
|
80
|
+
# with_enums scope
|
|
81
|
+
scope "with_#{enum_plural}", -> (sets_arr) {
|
|
82
|
+
where( enum_name => self.send( enum_plural ).slice(
|
|
83
|
+
*sets_arr.map{|set_name| self.try( "#{set_name}_#{enum_plural}" ) || set_name }.flatten.uniq.map(&:to_s) ).values )
|
|
84
|
+
} unless respond_to?("with_#{enum_plural}")
|
|
85
|
+
|
|
86
|
+
# without_enums scope
|
|
87
|
+
scope "without_#{enum_plural}", -> (sets_arr) {
|
|
88
|
+
where.not( id: self.send("with_#{enum_plural}", sets_arr) )
|
|
89
|
+
} unless respond_to?("without_#{enum_plural}")
|
|
122
90
|
|
|
123
|
-
|
|
91
|
+
|
|
92
|
+
# class.enum_set_values
|
|
93
|
+
define_singleton_method( "#{set_name}_#{enum_plural}" ) do
|
|
124
94
|
enum_vals
|
|
125
95
|
end
|
|
126
96
|
|
|
127
|
-
|
|
128
|
-
|
|
97
|
+
# class.enum_set_enums_i
|
|
98
|
+
define_singleton_method( "#{set_name}_#{enum_plural}_i" ) do
|
|
99
|
+
self.send( "#{enum_plural}" ).slice( *self.send("#{set_name}_#{enum_plural}") ).values
|
|
129
100
|
end
|
|
130
101
|
|
|
131
|
-
|
|
132
|
-
|
|
102
|
+
# t_... - are translation dependent methods
|
|
103
|
+
# class.t_enums_options
|
|
104
|
+
define_singleton_method( "t_#{set_name}_#{enum_plural}_options" ) do
|
|
105
|
+
return [["Enum translations call missed. Did you forget to call translate #{enum_name}"]*2] unless respond_to?( "t_#{enum_plural}_options_raw" )
|
|
106
|
+
|
|
107
|
+
send("t_#{enum_plural}_options_raw", send("t_#{set_name}_#{enum_plural}") )
|
|
133
108
|
end
|
|
134
109
|
|
|
135
|
-
|
|
136
|
-
|
|
110
|
+
# class.t_enums_options_i
|
|
111
|
+
define_singleton_method( "t_#{set_name}_#{enum_plural}_options_i" ) do
|
|
112
|
+
return [["Enum translations call missed. Did you forget to call translate #{enum_name}"]*2] unless respond_to?( "t_#{enum_plural}_options_raw_i" )
|
|
113
|
+
|
|
114
|
+
send("t_#{enum_plural}_options_raw_i", send("t_#{set_name}_#{enum_plural}") )
|
|
137
115
|
end
|
|
138
116
|
|
|
139
|
-
|
|
117
|
+
# instance.set_name?
|
|
118
|
+
define_method "#{set_name}?" do
|
|
119
|
+
self.send(enum_name) && ( enum_vals.include?( self.send(enum_name) ) || enum_vals.include?( self.send(enum_name).to_sym ))
|
|
120
|
+
end
|
|
140
121
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
122
|
+
# protected?
|
|
123
|
+
# class.t_setname_enums ( translations or humanizations subset for a given set )
|
|
124
|
+
define_singleton_method( "t_#{set_name}_#{enum_plural}" ) do
|
|
125
|
+
return [(["Enum translations call missed. Did you forget to call translate #{enum_name}"]*2)].to_h unless respond_to?( "t_#{enum_plural}" )
|
|
145
126
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
127
|
+
send( "t_#{enum_plural}" ).slice( *self.send("#{set_name}_#{enum_plural}") )
|
|
128
|
+
end
|
|
129
|
+
end
|
|
149
130
|
end
|
|
150
131
|
end
|
|
151
132
|
|
|
152
133
|
# Ex mass_assign_enum
|
|
153
|
-
# Used for mass assigning for collection
|
|
154
|
-
#
|
|
155
|
-
#
|
|
156
|
-
# If you need callbacks you can do like this: some_scope.each(&:new_stat!) but if you don't need callbacks and you
|
|
134
|
+
# Used for mass assigning for collection without callbacks it creates bang methods for collections using update_all.
|
|
135
|
+
# it's often case when you need bulk update without callbacks, so it's gets frustrating to repeat:
|
|
136
|
+
# some_scope.update_all(status: Request.statuses[:new_status], update_at: Time.now)
|
|
137
|
+
# If you need callbacks you can do like this: some_scope.each(&:new_stat!) but if you don't need callbacks and you have lots of records
|
|
138
|
+
# to change at once you need update_all
|
|
157
139
|
#
|
|
158
|
-
#
|
|
159
|
-
#
|
|
160
|
-
#
|
|
161
|
-
#
|
|
140
|
+
# mass_assign_enum( :status )
|
|
141
|
+
#
|
|
142
|
+
# class methods:
|
|
143
|
+
# in_cart! paid! in_warehouse! and so
|
|
162
144
|
#
|
|
163
145
|
# Console:
|
|
164
146
|
# request1.in_cart!
|
|
165
147
|
# request2.waiting_for_payment!
|
|
166
|
-
# Request.
|
|
167
|
-
# request1.
|
|
168
|
-
# request2.
|
|
148
|
+
# Request.with_statuses( :in_cart, :waiting_for_payment ).payed!
|
|
149
|
+
# request1.paid? # >> true
|
|
150
|
+
# request2.paid? # >> true
|
|
169
151
|
# request1.updated_at # >> Time.now
|
|
170
152
|
# defined?(Request::MassAssignEnum) # >> true
|
|
171
153
|
#
|
|
172
|
-
# order.requests.
|
|
173
|
-
# order.requests.
|
|
154
|
+
# order.requests.paid.all?(&:paid?) # >> true
|
|
155
|
+
# order.requests.paid.delivered!
|
|
174
156
|
# order.requests.map(&:status).uniq #>> [:delivered]
|
|
175
|
-
#
|
|
176
|
-
#
|
|
177
|
-
# Rem:
|
|
178
|
-
# mass_assign_enum accepts additional options as last argument.
|
|
179
|
-
# calling mass_assign_enum( :status ) actually is equal to call: mass_assign_enum( :status, { relation: true, association_relation: true } )
|
|
180
|
-
#
|
|
181
|
-
# Meaning:
|
|
182
157
|
|
|
183
|
-
|
|
158
|
+
def mass_assign_enum( *enums_names )
|
|
159
|
+
enums_names.each do |enum_name|
|
|
160
|
+
enum_vals = self.send( enum_name.to_s.pluralize )
|
|
184
161
|
|
|
185
|
-
|
|
186
|
-
|
|
162
|
+
enum_vals.keys.each do |enum_el|
|
|
163
|
+
define_singleton_method( "#{enum_el}!" ) do
|
|
164
|
+
self.update_all( {enum_name => enum_vals[enum_el]}.merge( self.column_names.include?('updated_at') ? {updated_at: Time.now} : {} ))
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# if app doesn't need internationalization, it may use humanize_enum to make enum user friendly
|
|
187
171
|
# class Request
|
|
188
|
-
#
|
|
189
|
-
#
|
|
172
|
+
# humanize_enum :status, {
|
|
173
|
+
# #locale dependent example with pluralization and lambda:
|
|
174
|
+
# payed: -> (t_self) { I18n.t("request.status.payed", count: t_self.sum ) }
|
|
175
|
+
#
|
|
176
|
+
# #locale dependent example with pluralization and proc:
|
|
177
|
+
# payed: Proc.new{ I18n.t("request.status.payed", count: self.sum ) }
|
|
178
|
+
#
|
|
179
|
+
# #locale independent:
|
|
180
|
+
# ready_for_shipment: "Ready to go!"
|
|
181
|
+
# }
|
|
190
182
|
# end
|
|
191
|
-
#
|
|
192
|
-
#
|
|
183
|
+
#
|
|
184
|
+
# Could be called multiple times, all humanization definitions will be merged under the hood:
|
|
185
|
+
# humanize_enum :status, {
|
|
186
|
+
# payed: I18n.t("scope.#{status}")
|
|
187
|
+
# }
|
|
188
|
+
# humanize_enum :status, {
|
|
189
|
+
# billed: I18n.t("scope.#{status}")
|
|
190
|
+
# }
|
|
191
|
+
#
|
|
192
|
+
#
|
|
193
|
+
# Example with block:
|
|
194
|
+
#
|
|
195
|
+
# humanize_enum :status do
|
|
196
|
+
# I18n.t("scope.#{status}")
|
|
193
197
|
# end
|
|
194
198
|
#
|
|
195
|
-
#
|
|
199
|
+
# in views select:
|
|
200
|
+
# f.select :status, Request.t_statuses_options
|
|
196
201
|
#
|
|
197
|
-
#
|
|
198
|
-
#
|
|
202
|
+
# in select in Active Admin filter
|
|
203
|
+
# collection: Request.t_statuses_options_i
|
|
204
|
+
#
|
|
205
|
+
# Rem: select options breaks when using lambda() with params
|
|
206
|
+
#
|
|
207
|
+
# Console:
|
|
208
|
+
# request.sum = 3
|
|
209
|
+
# request.payed!
|
|
210
|
+
# request.status # >> payed
|
|
211
|
+
# request.t_status # >> "Payed 3 dollars"
|
|
212
|
+
# Request.t_statuses # >> { in_cart: -> { I18n.t("request.status.in_cart") }, .... }
|
|
213
|
+
def humanize_enum( *args, &block )
|
|
214
|
+
enum_name = args.shift
|
|
215
|
+
localizations = args.pop
|
|
216
|
+
enum_plural = enum_name.to_s.pluralize
|
|
199
217
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
218
|
+
self.instance_eval do
|
|
219
|
+
|
|
220
|
+
#t_enum
|
|
221
|
+
define_method "t_#{enum_name}" do
|
|
222
|
+
t = block || localizations.try(:with_indifferent_access)[send(enum_name)]
|
|
223
|
+
if t.try(:lambda?)
|
|
224
|
+
t.try(:arity) == 1 && t.call( self ) || t.try(:call)
|
|
225
|
+
elsif t.is_a?(Proc)
|
|
226
|
+
instance_eval(&t)
|
|
227
|
+
else
|
|
228
|
+
t
|
|
229
|
+
end.to_s
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
@@localizations ||= {}.with_indifferent_access
|
|
233
|
+
# if localization is abscent than block must be given
|
|
234
|
+
@@localizations.merge!(
|
|
235
|
+
localizations.try(:with_indifferent_access) ||
|
|
236
|
+
localizations ||
|
|
237
|
+
send(enum_plural).keys.map{|en| [en, Proc.new{ self.new({ enum_name => en }).send("t_#{enum_name}") }] }.to_h.with_indifferent_access
|
|
238
|
+
)
|
|
239
|
+
#t_enums
|
|
240
|
+
define_singleton_method( "t_#{enum_plural}" ) do
|
|
241
|
+
@@localizations
|
|
242
|
+
end
|
|
205
243
|
|
|
206
|
-
|
|
244
|
+
#t_enums_options
|
|
245
|
+
define_singleton_method( "t_#{enum_plural}_options" ) do
|
|
246
|
+
send("t_#{enum_plural}_options_raw", send("t_#{enum_plural}") )
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
#t_enums_options_i
|
|
250
|
+
define_singleton_method( "t_#{enum_plural}_options_i" ) do
|
|
251
|
+
send("t_#{enum_plural}_options_raw_i", send("t_#{enum_plural}") )
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
define_method "t_#{enum_name}=" do |new_val|
|
|
255
|
+
send("#{enum_name}=", new_val)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
#protected?
|
|
259
|
+
define_singleton_method( "t_#{enum_plural}_options_raw_i" ) do |t_enum_set|
|
|
260
|
+
send("t_#{enum_plural}_options_raw", t_enum_set ).map do | key_val |
|
|
261
|
+
key_val[1] = send(enum_plural)[key_val[1]]
|
|
262
|
+
key_val
|
|
263
|
+
end
|
|
264
|
+
end
|
|
207
265
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
266
|
+
define_singleton_method( "t_#{enum_plural}_options_raw" ) do |t_enum_set|
|
|
267
|
+
t_enum_set.invert.to_a.map do | key_val |
|
|
268
|
+
# since all procs in t_enum are evaluated in context of a record than it's not always possible to create select options
|
|
269
|
+
if key_val[0].respond_to?(:call)
|
|
270
|
+
if key_val[0].try(:arity) < 1
|
|
271
|
+
key_val[0] = key_val[0].try(:call) rescue "Cannot create option for #{key_val[1]} ( proc fails to evaluate )"
|
|
272
|
+
else
|
|
273
|
+
key_val[0] = "Cannot create option for #{key_val[1]} because of a lambda"
|
|
274
|
+
end
|
|
212
275
|
end
|
|
276
|
+
key_val
|
|
213
277
|
end
|
|
214
278
|
end
|
|
215
|
-
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
alias localize_enum humanize_enum
|
|
282
|
+
|
|
283
|
+
# Simple way to translate enum.
|
|
284
|
+
# It use either given scope as second argument, or generated activerecord.attributes.model_name_underscore.enum_name
|
|
285
|
+
# If block is given than no scopes are taken in consider
|
|
286
|
+
def translate_enum( *args, &block )
|
|
287
|
+
enum_name = args.shift
|
|
288
|
+
enum_plural = enum_name.to_s.pluralize
|
|
289
|
+
t_scope = args.pop || "activerecord.attributes.#{self.name.underscore}.#{enum_plural}"
|
|
216
290
|
|
|
217
|
-
|
|
218
|
-
|
|
291
|
+
if block_given?
|
|
292
|
+
humanize_enum( enum_name, &block )
|
|
293
|
+
else
|
|
294
|
+
humanize_enum( enum_name, send(enum_plural).keys.map{|en| [ en, Proc.new{ I18n.t("#{t_scope}.#{en}") }] }.to_h )
|
|
219
295
|
end
|
|
220
296
|
end
|
|
221
297
|
|
|
298
|
+
# human_attribute_name is redefined for automation like this:
|
|
299
|
+
# p #{object.class.human_attribute_name( attr_name )}:
|
|
300
|
+
# p object.send(attr_name)
|
|
301
|
+
def human_attribute_name( name, options = {} )
|
|
302
|
+
# if name starts from t_ and there is a column with the last part then ...
|
|
303
|
+
name[0..1] == 't_' && column_names.include?(name[2..-1]) ? super( name[2..-1], options ) : super( name, options )
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
|
|
222
307
|
end
|
data/lib/enum_ext/version.rb
CHANGED
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.1
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- alekseyl
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2020-12-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -16,44 +16,100 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
19
|
+
version: 5.2.4.3
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
26
|
+
version: 5.2.4.3
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: minitest
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
27
41
|
- !ruby/object:Gem::Dependency
|
|
28
42
|
name: bundler
|
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
|
30
44
|
requirements:
|
|
31
|
-
- - "
|
|
45
|
+
- - ">="
|
|
32
46
|
- !ruby/object:Gem::Version
|
|
33
47
|
version: '1.11'
|
|
34
48
|
type: :development
|
|
35
49
|
prerelease: false
|
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
51
|
requirements:
|
|
38
|
-
- - "
|
|
52
|
+
- - ">="
|
|
39
53
|
- !ruby/object:Gem::Version
|
|
40
54
|
version: '1.11'
|
|
41
55
|
- !ruby/object:Gem::Dependency
|
|
42
56
|
name: rake
|
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
|
44
58
|
requirements:
|
|
45
|
-
- - "
|
|
59
|
+
- - ">="
|
|
46
60
|
- !ruby/object:Gem::Version
|
|
47
61
|
version: '10.0'
|
|
48
62
|
type: :development
|
|
49
63
|
prerelease: false
|
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
65
|
requirements:
|
|
52
|
-
- - "
|
|
66
|
+
- - ">="
|
|
53
67
|
- !ruby/object:Gem::Version
|
|
54
68
|
version: '10.0'
|
|
55
|
-
|
|
56
|
-
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rails-i18n
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '4'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '4'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: sqlite3
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: byebug
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
111
|
+
description: Enum extension, ads enum sets, mass-assign, localization, and some sugar
|
|
112
|
+
helpers.
|
|
57
113
|
email:
|
|
58
114
|
- leshchuk@gmail.com
|
|
59
115
|
executables: []
|
|
@@ -61,11 +117,15 @@ extensions: []
|
|
|
61
117
|
extra_rdoc_files: []
|
|
62
118
|
files:
|
|
63
119
|
- ".gitignore"
|
|
120
|
+
- ".travis.yml"
|
|
121
|
+
- CHANGELOG.md
|
|
64
122
|
- Gemfile
|
|
65
123
|
- Gemfile.lock
|
|
66
124
|
- LICENSE.txt
|
|
67
125
|
- README.md
|
|
68
126
|
- Rakefile
|
|
127
|
+
- bin/console
|
|
128
|
+
- bin/setup
|
|
69
129
|
- enum_ext.gemspec
|
|
70
130
|
- lib/enum_ext.rb
|
|
71
131
|
- lib/enum_ext/version.rb
|
|
@@ -73,7 +133,7 @@ homepage: https://github.com/alekseyl/enum_ext
|
|
|
73
133
|
licenses:
|
|
74
134
|
- MIT
|
|
75
135
|
metadata: {}
|
|
76
|
-
post_install_message:
|
|
136
|
+
post_install_message:
|
|
77
137
|
rdoc_options: []
|
|
78
138
|
require_paths:
|
|
79
139
|
- lib
|
|
@@ -88,9 +148,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
88
148
|
- !ruby/object:Gem::Version
|
|
89
149
|
version: '0'
|
|
90
150
|
requirements: []
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
signing_key:
|
|
151
|
+
rubygems_version: 3.1.2
|
|
152
|
+
signing_key:
|
|
94
153
|
specification_version: 4
|
|
95
|
-
summary: Enum extension, ads enum sets, mass-assign
|
|
154
|
+
summary: Enum extension, ads enum sets, mass-assign, localization, and some sugar
|
|
155
|
+
helpers.
|
|
96
156
|
test_files: []
|