enum_ext 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/enum_ext.rb +197 -0
- metadata +44 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4ffa90e0370f3f30ab49c181e22ae0912d145f13
|
4
|
+
data.tar.gz: eddf18cc4c9387c5598725692659fff237ab8d56
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 508e8720112409a3a3f68ff4274e09d8900a68e6154d921b5c2009e5cc599f9cefb3d621ac091a0d7dddd5363b49fedf5a28e36b3688285494768f21bfc36cc8
|
7
|
+
data.tar.gz: 65ff47b4104d223e663e6db03660a4d2c6378560fc174f5720ecd172c86f0045b60cc8130b99b29c1909a99aecb6ec6e05fc124c6180f451532dd88cc87e7e25
|
data/lib/enum_ext.rb
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
# Let's assume we have model Request with enum status, and we have model Order with requests like this:
|
2
|
+
# class Request
|
3
|
+
# extend EnumExt
|
4
|
+
# belongs_to :order
|
5
|
+
# enum status: [ :in_cart, :waiting_for_payment, :payed, :ready_for_shipment, :on_delivery, :delivered ]
|
6
|
+
# end
|
7
|
+
#
|
8
|
+
# class Order
|
9
|
+
# has_many :requests
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
module EnumExt
|
13
|
+
# Ex using localize_enum with Request
|
14
|
+
# class Request
|
15
|
+
# ...
|
16
|
+
# localize_enum :status, {
|
17
|
+
#
|
18
|
+
# #locale dependent example ( it dynamically use current locale ):
|
19
|
+
# in_cart: -> { I18n.t("request.status.in_cart") },
|
20
|
+
|
21
|
+
# #locale dependent example with pluralization:
|
22
|
+
# payed: -> (t_self) { I18n.t("request.status.payed", count: t_self.sum ) }
|
23
|
+
#
|
24
|
+
# #locale independent:
|
25
|
+
# ready_for_shipment: "Ready to go!"
|
26
|
+
#
|
27
|
+
#
|
28
|
+
# }
|
29
|
+
# end
|
30
|
+
|
31
|
+
# Console:
|
32
|
+
# request.sum = 3
|
33
|
+
# request.payed!
|
34
|
+
# request.status # >> payed
|
35
|
+
# request.t_status # >> "Payed 3 dollars"
|
36
|
+
# Request.t_statuses # >> { in_cart: -> { I18n.t("request.status.in_cart") }, .... }
|
37
|
+
|
38
|
+
# if you need some substitution you can go like this
|
39
|
+
# localize_enum :status, {
|
40
|
+
# ..
|
41
|
+
# delivered: "Delivered at: %{date}"
|
42
|
+
# }
|
43
|
+
# request.delivered!
|
44
|
+
# request.t_status % {date: Time.now.to_s} # >> Delivered at: 05.02.2016
|
45
|
+
#
|
46
|
+
# Using in select:
|
47
|
+
# f.select :status, Request.t_statuses.invert.to_a
|
48
|
+
#
|
49
|
+
def localize_enum( enum_name, localizations )
|
50
|
+
self.instance_eval do
|
51
|
+
define_singleton_method( "t_#{enum_name.to_s.pluralize}" ) do
|
52
|
+
localizations.try(:with_indifferent_access) || localizations
|
53
|
+
end
|
54
|
+
define_method "t_#{enum_name}" do
|
55
|
+
t = localizations[send(enum_name)]
|
56
|
+
( t.try(:arity) == 1 && t.call( self ) || t.try(:call) || t).to_s
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Ex ext_enum_sets
|
62
|
+
# This method intend for creating and using some sets of enum values with similar to original enum syntax
|
63
|
+
# it creates: scopes for subsets like enum did, instance method with ? similar to enum methods, and methods like Request.statuses
|
64
|
+
# Usually I supply comment near method call to remember what methods will be defined
|
65
|
+
# class Request
|
66
|
+
# ...
|
67
|
+
# #instance non_payed?, delivery_set?, in_warehouse?
|
68
|
+
# #class scopes: non_payed, delivery_set, in_warehouse
|
69
|
+
# #class scopes: with_statuses, without_statuses
|
70
|
+
# #class non_payed_statuses, delivery_set_statuses ( = [:in_cart, :waiting_for_payment], [:ready_for_shipment, :on_delivery, :delivered].. )
|
71
|
+
# ext_enum_sets :status, {
|
72
|
+
# non_payed: [:in_cart, :waiting_for_payment],
|
73
|
+
# delivery_set: [:ready_for_shipment, :on_delivery, :delivered] # for shipping department for example
|
74
|
+
# in_warehouse: [:ready_for_shipment] # it's just for example below
|
75
|
+
# }
|
76
|
+
# end
|
77
|
+
|
78
|
+
# Console:
|
79
|
+
# request.waiting_for_payment!
|
80
|
+
# request.non_payed? # >> true
|
81
|
+
|
82
|
+
# Request.non_payed.exists?(request) # >> true
|
83
|
+
# Request.delivery_set.exists?(request) # >> false
|
84
|
+
|
85
|
+
# Request.non_payed_statuses # >> [:in_cart, :waiting_for_payment]
|
86
|
+
#
|
87
|
+
# Request.with_statuses( :payed, :in_cart ) # >> scope for all in_cart and payed requests
|
88
|
+
# Request.without_statuses( :payed ) # >> scope for all requests with statuses not eq to payed
|
89
|
+
# Request.without_statuses( :payed, :non_payed ) # >> scope all requests with statuses not eq to payed and in_cart + waiting_for_payment
|
90
|
+
#
|
91
|
+
|
92
|
+
#Rem:
|
93
|
+
# ext_enum_sets can be called twice defining a superpositoin of already defined sets:
|
94
|
+
# class Request
|
95
|
+
# ...
|
96
|
+
# ext_enum_sets (... first time call )
|
97
|
+
# ext_enum_sets :status, {
|
98
|
+
# already_payed: ( [:payed] | delivery_set_statuses ),
|
99
|
+
# outside_wharehouse: ( delivery_set_statuses - in_warehouse_statuses )... any other array operations like &, + and so can be used
|
100
|
+
# }
|
101
|
+
def ext_enum_sets( enum_name, options )
|
102
|
+
self.instance_eval do
|
103
|
+
options.each do |set_name, enum_vals|
|
104
|
+
scope set_name, -> { where( enum_name => self.send( enum_name.to_s.pluralize ).slice( *enum_vals.map(&:to_s) ).values ) }
|
105
|
+
|
106
|
+
define_singleton_method( "#{set_name}_#{enum_name.to_s.pluralize}" ) do
|
107
|
+
enum_vals
|
108
|
+
end
|
109
|
+
|
110
|
+
define_method "#{set_name}?" do
|
111
|
+
self.send(enum_name) && ( enum_vals.include?( self.send(enum_name) ) || enum_vals.include?( self.send(enum_name).to_sym ))
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
scope "with_#{enum_name.to_s.pluralize}", -> (sets_arr) {
|
117
|
+
where( enum_name => self.send( enum_name.to_s.pluralize ).slice(
|
118
|
+
*sets_arr.map{|set_name| self.try( "#{set_name}_#{enum_name.to_s.pluralize}" ) || set_name }.flatten.uniq.map(&:to_s) ).values )
|
119
|
+
} unless respond_to?("with_#{enum_name.to_s.pluralize}")
|
120
|
+
|
121
|
+
scope "without_#{enum_name.to_s.pluralize}", -> (sets_arr) {
|
122
|
+
where.not( id: self.send("with_#{enum_name.to_s.pluralize}", sets_arr) )
|
123
|
+
} unless respond_to?("without_#{enum_name.to_s.pluralize}")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Ex mass_assign_enum
|
128
|
+
# Used for mass assigning for collection, it creates dynamically nested module with methods similar to enum bang methods, and includes it to relation classes
|
129
|
+
# Behind the scene it creates bang methods for collections using update_all.
|
130
|
+
# it's often case when I need bulk update without callbacks, so it's gets frustrating to repeat: some_scope.update_all(status: Request.statuses[:new_status], update_at: Time.now)
|
131
|
+
# If you need callbacks you can do like this: some_scope.each(&:new_stat!) but if you don't need callbacks and you has hundreds and thousands of records to change at once you need update_all
|
132
|
+
#
|
133
|
+
# class Request
|
134
|
+
# ...
|
135
|
+
# mass_assign_enum( :status )
|
136
|
+
# end
|
137
|
+
#
|
138
|
+
# Console:
|
139
|
+
# request1.in_cart!
|
140
|
+
# request2.waiting_for_payment!
|
141
|
+
# Request.non_payed.payed!
|
142
|
+
# request1.payed? # >> true
|
143
|
+
# request2.payed? # >> true
|
144
|
+
# request1.updated_at # >> Time.now
|
145
|
+
# Request.respond_to?('::MassAssignEnum') # >> true
|
146
|
+
#
|
147
|
+
# order.requests.already_payed.all?(&:already_payed?) # >> true
|
148
|
+
# order.requests.already_payed.delivered!
|
149
|
+
# order.requests.map(&:status).uniq #>> [:delivered]
|
150
|
+
#
|
151
|
+
#
|
152
|
+
# Rem:
|
153
|
+
# mass_assign_enum accepts additional options as last argument.
|
154
|
+
# calling mass_assign_enum( :status ) actually is equal to call: mass_assign_enum( :status, { relation: true, association_relation: true } )
|
155
|
+
#
|
156
|
+
# Meaning:
|
157
|
+
|
158
|
+
# relation: true - Request.some_scope.payed! - works
|
159
|
+
|
160
|
+
# association_relation: true - Order.first.requests.scope.new_stat! - works
|
161
|
+
# but it wouldn't works without 'scope' part! If you want to use it without 'scope' you may do it this way:
|
162
|
+
# class Request
|
163
|
+
# ...
|
164
|
+
# mass_assign_enum( :status, association_relation: false )
|
165
|
+
# end
|
166
|
+
# class Order
|
167
|
+
# has_many :requests, extend: Request::MassAssignEnum
|
168
|
+
# end
|
169
|
+
#
|
170
|
+
# Order.first.requests.respond_to?(:in_cart!) # >> true
|
171
|
+
#
|
172
|
+
# Rem2:
|
173
|
+
# you can mass-assign more than one enum ::MassAssignEnum module will contain mass assign for both. It will break nothing since all enum name must be uniq across model
|
174
|
+
|
175
|
+
def mass_assign_enum( *options )
|
176
|
+
relation_options = (options[-1].is_a?(Hash) && options.pop || {relation: true, association_relation: true} ).with_indifferent_access
|
177
|
+
enums_names = options
|
178
|
+
enums_names.each do |enum_name|
|
179
|
+
enum_vals = self.send( enum_name.to_s.pluralize )
|
180
|
+
|
181
|
+
mass_ass_module = ( self.try( "::MassAssignEnum" ) || Module.new )
|
182
|
+
|
183
|
+
mass_ass_module.instance_eval do
|
184
|
+
enum_vals.keys.each do |enum_el|
|
185
|
+
define_method( "#{enum_el}!" ) do
|
186
|
+
self.update_all( {enum_name => enum_vals[enum_el]}.merge( self.column_names.include?('updated_at') ? {updated_at: Time.now} : {} ))
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
self.const_set( :MassAssignEnum, mass_ass_module ) unless self.try( '::MassAssignEnum' )
|
191
|
+
|
192
|
+
self::ActiveRecord_Relation.include( self::MassAssignEnum ) if relation_options[:relation]
|
193
|
+
self::ActiveRecord_AssociationRelation.include( self::MassAssignEnum ) if relation_options[:association_relation]
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
metadata
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: enum_ext
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Leshchuk Alexey
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-02-22 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Some sugar extention for rails enum
|
14
|
+
email: leshchuk@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/enum_ext.rb
|
20
|
+
homepage: http://rubygems.org/gems/hola
|
21
|
+
licenses:
|
22
|
+
- MIT
|
23
|
+
metadata: {}
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- lib
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
requirements: []
|
39
|
+
rubyforge_project:
|
40
|
+
rubygems_version: 2.5.1
|
41
|
+
signing_key:
|
42
|
+
specification_version: 4
|
43
|
+
summary: Enum extention!
|
44
|
+
test_files: []
|