model_subsets 0.0.1 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/model_subsets.rb +231 -120
- data/lib/model_subsets/class_methods.rb +130 -0
- data/lib/model_subsets/version.rb +1 -1
- data/model_subsets.gemspec +3 -0
- metadata +20 -3
data/lib/model_subsets.rb
CHANGED
@@ -2,148 +2,259 @@ require "model_subsets/version"
|
|
2
2
|
|
3
3
|
module ModelSubsets
|
4
4
|
|
5
|
-
|
6
|
-
def self.included(base)
|
7
|
-
base.extend ModelSubsets::ClassMethods
|
8
|
-
end
|
5
|
+
extend ActiveSupport::Concern
|
9
6
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
7
|
+
# Return current subset fieldsets list
|
8
|
+
#
|
9
|
+
# @return [ Array ]
|
10
|
+
#
|
11
|
+
# @since 0.0.2
|
12
|
+
def fieldsets
|
13
|
+
subset_content[:fieldsets] if valid_subset?
|
14
|
+
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
# Whether subset includes a fieldset
|
17
|
+
#
|
18
|
+
# @example Check if a user has fieldset :common
|
19
|
+
# user.has_fieldset? :common
|
20
|
+
#
|
21
|
+
# @param [ Symbol ] name The fieldset name
|
22
|
+
#
|
23
|
+
# @return [ Boolean ]
|
24
|
+
#
|
25
|
+
# @since 0.0.2
|
26
|
+
def has_fieldset? name
|
27
|
+
fieldsets.include?(name) if valid_subset?
|
28
|
+
end
|
19
29
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
30
|
+
# Whether subset is included in a subsets scope
|
31
|
+
#
|
32
|
+
# @example Check if current subset is in :users subsets scope
|
33
|
+
# person.in_subset_scope? :users
|
34
|
+
#
|
35
|
+
# @param [ Symbol ] name The subsets scope name
|
36
|
+
#
|
37
|
+
# @return [ Boolean ]
|
38
|
+
#
|
39
|
+
# @since 0.0.4
|
40
|
+
def in_subsets_scope? name
|
41
|
+
self.class.subsets_scope(name).include? subset.to_sym
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns current subset content
|
45
|
+
# An empty Hash is returned if subset is not defined
|
46
|
+
#
|
47
|
+
# @return [ Hash ]
|
48
|
+
#
|
49
|
+
# @since 0.0.2
|
50
|
+
def subset_content
|
51
|
+
self.class.subsets[subset.to_sym] if valid_subset?
|
52
|
+
end
|
53
|
+
|
54
|
+
# Whether a subset fieldset includes a field
|
55
|
+
# It only checks if the field is included in current subset fieldsets, not if the field is a column in the model
|
56
|
+
#
|
57
|
+
# @example Check if a user uses field :name
|
58
|
+
# user.has_field? :name
|
59
|
+
#
|
60
|
+
# @param [ Symbol ] name The field name
|
61
|
+
#
|
62
|
+
# @return [ Boolean ]
|
63
|
+
#
|
64
|
+
# @since 0.0.2
|
65
|
+
def subset_field? name
|
66
|
+
subset_fields.include?(name) if subset_fields
|
67
|
+
end
|
68
|
+
|
69
|
+
# Return current subset fields list
|
70
|
+
#
|
71
|
+
# @return [ Array ]
|
72
|
+
#
|
73
|
+
# @since 0.0.2
|
74
|
+
def subset_fields
|
75
|
+
self.class.subset_fields(subset.to_sym) if valid_subset?
|
76
|
+
end
|
25
77
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
78
|
+
# Whether current subset id is defined
|
79
|
+
#
|
80
|
+
# @example Use valid_subset? as a model validation
|
81
|
+
# validate :valid_subset?
|
82
|
+
#
|
83
|
+
# @return [ Boolean ]
|
84
|
+
#
|
85
|
+
# @since 0.0.2
|
86
|
+
def valid_subset?
|
87
|
+
return true if self.class.subsets.keys.include?(subset.to_s.to_sym)
|
88
|
+
errors.add(:subset, :invalid) if respond_to?(:errors)
|
89
|
+
false
|
90
|
+
end
|
91
|
+
|
92
|
+
module ClassMethods
|
93
|
+
|
94
|
+
# Defines a fieldset
|
95
|
+
#
|
96
|
+
# @example Define fieldset :login including fields :username and :password
|
97
|
+
# fieldset :login, :username, :password
|
98
|
+
#
|
99
|
+
# @param [ Symbol ] name The fieldset name
|
100
|
+
# @param [ Array ] *args Fields names
|
101
|
+
#
|
102
|
+
# @since 0.0.2
|
103
|
+
def fieldset name, *args
|
104
|
+
@fieldsets ||= {}
|
105
|
+
@fieldsets[name] = args
|
30
106
|
end
|
107
|
+
|
108
|
+
# Defines a subset
|
109
|
+
# If no fieldset is included, all defined fieldsets will be included by default
|
110
|
+
# If fieldsets are defined on an extended subset, parents fieldsets will be ignored
|
111
|
+
#
|
112
|
+
# @example Define subset :user, which is a person able to login
|
113
|
+
# subset :user, extends: :person, with: :login, scopes: :users
|
114
|
+
#
|
115
|
+
# @param [ Symbol ] name The subset name
|
116
|
+
# @param [ Hash ] options The options to pass to the subset
|
117
|
+
#
|
118
|
+
# @option options [ Boolean ] :template Whether subset is a template (only used as an extend)
|
119
|
+
# @option options [ Symbol ] :group Subset group name
|
120
|
+
# @option options [ Symbol, Array ] :fieldsets Explicit fieldsets list. Overrides default list (all or herited)
|
121
|
+
# @option options [ Symbol, Array ] :scopes The scopes in which subset will be included
|
122
|
+
# @option options [ Symbol, Array ] :extends Parent subsets
|
123
|
+
# @option options [ Symbol, Array ] :with Fieldsets to be added to herited fieldsets
|
124
|
+
# @option options [ Symbol, Array ] :only Filters fieldsets to remove fielsets not being in this list
|
125
|
+
# @option options [ Symbol, Array ] :except Filters fieldsets to remove fieldsets being in this list
|
126
|
+
#
|
127
|
+
# @since 0.0.2
|
128
|
+
def subset name, options = {}
|
129
|
+
@subsets ||= {}
|
130
|
+
@subsets_scopes ||= {}
|
131
|
+
|
132
|
+
options[:fieldsets] = [options[:fieldsets]] unless options[:fieldsets].blank? || options[:fieldsets].is_a?(Array)
|
31
133
|
|
32
|
-
|
134
|
+
# Subset is an extension
|
135
|
+
if options[:extends]
|
33
136
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
137
|
+
# Force extends option to Array
|
138
|
+
options[:extends] = [options[:extends]] unless options[:extends].is_a?(Array)
|
139
|
+
options[:extends].each do |source_subset|
|
140
|
+
next unless @subsets.has_key? source_subset
|
141
|
+
source_options = @subsets[source_subset].clone
|
142
|
+
source_options.delete :template
|
143
|
+
options = source_options.merge options
|
40
144
|
end
|
41
|
-
@fieldsets ||= {}
|
42
|
-
@fieldsets[fieldset] = args
|
43
|
-
end
|
44
145
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
subsets[subset][:fieldsets].each do |fieldset|
|
50
|
-
fieldset = @fieldsets[fieldset].is_a?(Array) ? @fieldsets[fieldset] : [@fieldsets[fieldset]]
|
51
|
-
subset_fields |= fieldset
|
146
|
+
# Handle additional fieldsets list
|
147
|
+
if options[:with]
|
148
|
+
options[:with] = [options[:with]] unless options[:with].is_a?(Array)
|
149
|
+
options[:fieldsets] |= options[:with]
|
52
150
|
end
|
53
|
-
|
151
|
+
|
152
|
+
# Include all fieldsets by default
|
153
|
+
elsif options[:fieldsets].blank?
|
154
|
+
options[:fieldsets] = @fieldsets.keys
|
54
155
|
end
|
55
156
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
@subsets_config[subset] = options
|
157
|
+
# Handle inclusion list
|
158
|
+
if options[:only]
|
159
|
+
options[:only] = [options[:only]] unless options[:only].is_a?(Array)
|
160
|
+
options[:fieldsets] &= options[:only]
|
61
161
|
end
|
62
162
|
|
63
|
-
#
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
# Cache builded subsets
|
69
|
-
return @subsets unless @subsets.blank? || options[:purge]
|
70
|
-
|
71
|
-
@subsets = {}
|
72
|
-
|
73
|
-
@subsets_config.each do |subset, options|
|
74
|
-
# Can't define same subset twice
|
75
|
-
raise "subset '#{subset} is already defined" if @subsets.has_key? subset
|
76
|
-
|
77
|
-
# Subset is an extension
|
78
|
-
if options[:extends]
|
79
|
-
|
80
|
-
# Force extends option to Array
|
81
|
-
options[:extends] = [options[:extends]] unless options[:extends].is_a? Array
|
82
|
-
options[:extends].each do |source_subset|
|
83
|
-
next unless @subsets.has_key? source_subset
|
84
|
-
source_options = @subsets[source_subset].clone
|
85
|
-
source_options.delete :abstract
|
86
|
-
options = source_options.merge options
|
87
|
-
end
|
88
|
-
|
89
|
-
# Handle additional fieldsets list
|
90
|
-
if options[:with]
|
91
|
-
options[:with] = [options[:with]] unless options[:with].is_a? Array
|
92
|
-
options[:fieldsets] |= options[:with]
|
93
|
-
end
|
94
|
-
|
95
|
-
else
|
96
|
-
# Include all fieldsets by default
|
97
|
-
options[:fieldsets] = @fieldsets.keys
|
98
|
-
end
|
99
|
-
|
100
|
-
# Handle inclusion list
|
101
|
-
if options[:only]
|
102
|
-
options[:only] = [options[:only]] unless options[:only].is_a? Array
|
103
|
-
options[:fieldsets] &= options[:only]
|
104
|
-
end
|
105
|
-
|
106
|
-
# Handle exclusion list
|
107
|
-
if options[:except]
|
108
|
-
options[:except] = [options[:except]] unless options[:except].is_a? Array
|
109
|
-
options[:fieldsets] -= options[:except]
|
110
|
-
end
|
111
|
-
|
112
|
-
# Cleanup
|
113
|
-
options[:fieldsets] = options[:fieldsets].uniq & @fieldsets.keys
|
114
|
-
remove_options = [:extends, :with, :only, :except]
|
115
|
-
options = options.clone
|
116
|
-
options.delete_if{ |key, value| remove_options.include?(key) }
|
117
|
-
@subsets[subset] = options
|
118
|
-
end
|
163
|
+
# Handle exclusion list
|
164
|
+
if options[:except]
|
165
|
+
options[:except] = [options[:except]] unless options[:except].is_a?(Array)
|
166
|
+
options[:fieldsets] -= options[:except]
|
167
|
+
end
|
119
168
|
|
120
|
-
|
169
|
+
# Handle scopes
|
170
|
+
options[:scopes] ||= []
|
171
|
+
options[:scopes] = [options[:scopes]] unless options[:scopes].is_a?(Array)
|
172
|
+
options[:scopes].each do |subset_scope|
|
173
|
+
@subsets_scopes[subset_scope] ||= []
|
174
|
+
@subsets_scopes[subset_scope] << name unless options[:template]
|
175
|
+
scope subset_scope, where(:subset.in => @subsets_scopes[subset_scope])
|
121
176
|
end
|
122
177
|
|
123
|
-
#
|
124
|
-
|
125
|
-
|
126
|
-
|
178
|
+
# Cleanup
|
179
|
+
options[:fieldsets] = options[:fieldsets].uniq & @fieldsets.keys
|
180
|
+
remove_options = [:extends, :with, :only, :except]
|
181
|
+
options = options.clone
|
182
|
+
options.delete_if{ |key, value| remove_options.include?(key) }
|
127
183
|
|
128
|
-
|
129
|
-
|
184
|
+
# Register subset
|
185
|
+
@subsets[name] = options
|
186
|
+
end
|
130
187
|
|
131
|
-
|
132
|
-
|
188
|
+
# Return subset fields list
|
189
|
+
#
|
190
|
+
# @example Get fields included in subset :user of model Person
|
191
|
+
# Person.subset_fields :user
|
192
|
+
# => [ :name, :givenname, :username, :password ]
|
193
|
+
#
|
194
|
+
# @params [ Symbol ] name The subset name
|
195
|
+
#
|
196
|
+
# @returns [ Array ]
|
197
|
+
#
|
198
|
+
# @since 0.0.1
|
199
|
+
def subset_fields name
|
200
|
+
return unless subsets.has_key?(name) && subsets[name].has_key?(:fieldsets)
|
201
|
+
subset_fields = []
|
202
|
+
subsets[name][:fieldsets].each do |fieldset|
|
203
|
+
fieldset = @fieldsets[fieldset].is_a?(Array) ? @fieldsets[fieldset] : [@fieldsets[fieldset]]
|
204
|
+
subset_fields |= fieldset
|
205
|
+
end
|
206
|
+
subset_fields.uniq
|
207
|
+
end
|
133
208
|
|
134
|
-
|
209
|
+
# Return builded subsets
|
210
|
+
#
|
211
|
+
# @return [ Hash ]
|
212
|
+
#
|
213
|
+
# @since 0.0.1
|
214
|
+
def subsets
|
215
|
+
@subsets.reject{ |name, options| options[:template] }
|
216
|
+
end
|
135
217
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
218
|
+
# Provides grouped subsets list, formatted for use with grouped collection select
|
219
|
+
#
|
220
|
+
# @return [ Array ]
|
221
|
+
#
|
222
|
+
# @since 0.0.1
|
223
|
+
def subsets_groups
|
224
|
+
groups = {}
|
225
|
+
i18n_group = {}
|
141
226
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
227
|
+
subsets.each do |subset, options|
|
228
|
+
options[:group] = :default unless options[:group]
|
229
|
+
i18n_subset = self.human_attribute_name("subsets.#{subset}")
|
230
|
+
i18n_group[options[:group]] ||= self.human_attribute_name("subsets.#{options[:group]}")
|
231
|
+
groups[i18n_group[options[:group]]] ||= [options[:group], {}]
|
232
|
+
groups[i18n_group[options[:group]]].last[i18n_subset] = subset
|
147
233
|
end
|
234
|
+
|
235
|
+
# Rearrange groups
|
236
|
+
groups = groups.sort
|
237
|
+
groups.map do |group|
|
238
|
+
[group.last.first, group.first, group.last.last.sort]
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# Return subsets included of a subsets scope
|
243
|
+
#
|
244
|
+
# @return [ Array ]
|
245
|
+
#
|
246
|
+
# @since 0.0.2
|
247
|
+
def subsets_scope name
|
248
|
+
subsets_scopes[name]
|
249
|
+
end
|
250
|
+
|
251
|
+
# Return subsets scopes list
|
252
|
+
#
|
253
|
+
# @return [ Array ]
|
254
|
+
#
|
255
|
+
# @since 0.0.2
|
256
|
+
def subsets_scopes
|
257
|
+
@subsets_scopes
|
148
258
|
end
|
259
|
+
end
|
149
260
|
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module ModelSubsets
|
2
|
+
module ClassMethods
|
3
|
+
|
4
|
+
# Creates a fieldset
|
5
|
+
def fieldset *args
|
6
|
+
fieldset = args.shift
|
7
|
+
raise "fieldset id must be a Symbol (#{fieldset.class} given)" unless fieldset.is_a? Symbol
|
8
|
+
raise "fieldset fields must be an Array (#{args.class} given)" unless args.is_a? Array
|
9
|
+
args.each do |field|
|
10
|
+
raise "field name must be an Symbol (#{field.class} given)" unless field.is_a? Symbol
|
11
|
+
end
|
12
|
+
@fieldsets ||= {}
|
13
|
+
@fieldsets[fieldset] = args
|
14
|
+
end
|
15
|
+
|
16
|
+
# Creates a subset
|
17
|
+
def subset subset, options = {}
|
18
|
+
raise "subset id must be a Symbol (#{subset.class} given)" unless subset.is_a? Symbol
|
19
|
+
raise "subset options must be a Hash (#{options.class} given)" unless options.is_a? Hash
|
20
|
+
@subsets_config ||= {}
|
21
|
+
@subsets_config[subset] = options
|
22
|
+
end
|
23
|
+
|
24
|
+
# Provides subset fieldset list
|
25
|
+
def subset_fieldset subset
|
26
|
+
return unless subsets.has_key?(subset) && subsets[subset].has_key?(:fieldsets)
|
27
|
+
subset_fields = []
|
28
|
+
subsets[subset][:fieldsets].each do |fieldset|
|
29
|
+
fieldset = @fieldsets[fieldset].is_a?(Array) ? @fieldsets[fieldset] : [@fieldsets[fieldset]]
|
30
|
+
subset_fields |= fieldset
|
31
|
+
end
|
32
|
+
subset_fields.uniq
|
33
|
+
end
|
34
|
+
|
35
|
+
# Provides subsets with builded extends & fieldsets
|
36
|
+
def subsets options = {}
|
37
|
+
@subsets_config ||= {}
|
38
|
+
raise "subsets config must ba a Hash (#{@subsets_config.class} given)" unless @subsets_config.is_a? Hash
|
39
|
+
|
40
|
+
# Cache builded subsets
|
41
|
+
return @subsets unless @subsets.blank? || options[:purge]
|
42
|
+
|
43
|
+
@subsets = {}
|
44
|
+
@scopes = {}
|
45
|
+
|
46
|
+
@subsets_config.each do |subset, options|
|
47
|
+
# Can't define same subset twice
|
48
|
+
raise "subset '#{subset} is already defined" if @subsets.has_key? subset
|
49
|
+
|
50
|
+
# Subset is an extension
|
51
|
+
if options[:extends]
|
52
|
+
|
53
|
+
# Force extends option to Array
|
54
|
+
options[:extends] = [options[:extends]] unless options[:extends].is_a? Array
|
55
|
+
options[:extends].each do |source_subset|
|
56
|
+
next unless @subsets.has_key? source_subset
|
57
|
+
source_options = @subsets[source_subset].clone
|
58
|
+
source_options.delete :abstract
|
59
|
+
options = source_options.merge options
|
60
|
+
end
|
61
|
+
|
62
|
+
# Handle additional fieldsets list
|
63
|
+
if options[:with]
|
64
|
+
options[:with] = [options[:with]] unless options[:with].is_a? Array
|
65
|
+
options[:fieldsets] |= options[:with]
|
66
|
+
end
|
67
|
+
|
68
|
+
else
|
69
|
+
# Include all fieldsets by default
|
70
|
+
options[:fieldsets] = @fieldsets.keys unless options[:fieldsets].is_a? Array
|
71
|
+
end
|
72
|
+
|
73
|
+
# Handle inclusion list
|
74
|
+
if options[:only]
|
75
|
+
options[:only] = [options[:only]] unless options[:only].is_a? Array
|
76
|
+
options[:fieldsets] &= options[:only]
|
77
|
+
end
|
78
|
+
|
79
|
+
# Handle exclusion list
|
80
|
+
if options[:except]
|
81
|
+
options[:except] = [options[:except]] unless options[:except].is_a? Array
|
82
|
+
options[:fieldsets] -= options[:except]
|
83
|
+
end
|
84
|
+
|
85
|
+
# Handle scopes
|
86
|
+
options[:scopes] = [options[:scopes]] unless options[:scopes].is_a? Array
|
87
|
+
options[:scopes].each do |scope|
|
88
|
+
@scopes[scope] ||= []
|
89
|
+
@scopes[scope] << subset
|
90
|
+
end
|
91
|
+
|
92
|
+
# Cleanup
|
93
|
+
options[:fieldsets] = options[:fieldsets].uniq & @fieldsets.keys
|
94
|
+
remove_options = [:extends, :with, :only, :except]
|
95
|
+
options = options.clone
|
96
|
+
options.delete_if{ |key, value| remove_options.include?(key) }
|
97
|
+
@subsets[subset] = options
|
98
|
+
end
|
99
|
+
|
100
|
+
@subsets = @subsets.reject{|key, value| value[:abstract] == true}
|
101
|
+
end
|
102
|
+
|
103
|
+
# Provides subsets groups list formatted for use with grouped collection select
|
104
|
+
def subsets_groups
|
105
|
+
groups = {}
|
106
|
+
i18n_group = {}
|
107
|
+
|
108
|
+
subsets.each do |subset, options|
|
109
|
+
raise "subset id must be a Symbol (#{subset.class} given)" unless subset.is_a? Symbol
|
110
|
+
|
111
|
+
# Set default group
|
112
|
+
options[:group] = :default unless options[:group]
|
113
|
+
|
114
|
+
raise "group id must be a Symbol (#{options[:group].class} given)" unless options[:group].is_a? Symbol
|
115
|
+
|
116
|
+
i18n_subset = self.human_attribute_name("subsets.#{subset}")
|
117
|
+
i18n_group[options[:group]] ||= self.human_attribute_name("subsets.#{options[:group]}")
|
118
|
+
groups[i18n_group[options[:group]]] ||= [options[:group], {}]
|
119
|
+
groups[i18n_group[options[:group]]].last[i18n_subset] = subset
|
120
|
+
end
|
121
|
+
|
122
|
+
# Rearrange groups
|
123
|
+
groups = groups.sort
|
124
|
+
groups.map do |group|
|
125
|
+
[group.last.first, group.first, group.last.last.sort]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
data/model_subsets.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: model_subsets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-07-
|
13
|
-
dependencies:
|
12
|
+
date: 2012-07-23 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activemodel
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.1'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.1'
|
14
30
|
description: ModelSubsets provides ability to split a single model into fields and
|
15
31
|
properties subsets
|
16
32
|
email:
|
@@ -25,6 +41,7 @@ files:
|
|
25
41
|
- README.md
|
26
42
|
- Rakefile
|
27
43
|
- lib/model_subsets.rb
|
44
|
+
- lib/model_subsets/class_methods.rb
|
28
45
|
- lib/model_subsets/version.rb
|
29
46
|
- model_subsets.gemspec
|
30
47
|
homepage: https://github.com/porecreat/model_subets
|