xsdk-scaffold-rails 0.1.4.3 → 0.1.8

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: 8137485ac88425560227d41abc1616a13a7a1868e7b9663ea0b3161f6b6b9e37
4
- data.tar.gz: dc8f81e0ea31be00347837417e1ce3ae666a602b83e7f7fb528763cc568fd52f
3
+ metadata.gz: 108cdf26bc4f923371e65b2a9b9f2a5329e6873cca09ae947060b6937d57bbef
4
+ data.tar.gz: b2af28bc2f01ff06ba271482a0e62a83ee8f9ff904f2e07e3fa8a792223430c3
5
5
  SHA512:
6
- metadata.gz: ac50a6a9ef3b080ea7ab2e183645d87a42f2e2573bbe876051e5ae8624d137966405b048b93ce59741aed06d9f9a7e348dd481f3a46545e8cf2a17308f39014f
7
- data.tar.gz: 52d2f9c5dcf6da229d90a97f7adf4f720a4f3db3e55d13bcc33585479eef50c490cc0219537f9cf1e584a981042bbd5ef4453257ca062f3c2df02e45c14f6b27
6
+ metadata.gz: 147f2ddd341e232b7bc2892aec51abec222ffaded11d6557385e202c1983e9d8318236edfde503bae09b620b73d0f43b43d15125d1beba954f1e28a525c80556
7
+ data.tar.gz: 816c60a6133969e2120ff2c417dee9acd1aeba8060d86a952b3c4b3fc72e6551bc7af1b98bf21616d309765f1c9909f9c200e5c7b8538d943cc86f467eae6e18
data/Gemfile CHANGED
@@ -1,7 +1,17 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in xsdk-scaffold-rails.gemspec
4
4
  gemspec
5
5
 
6
- gem "rake", "~> 12.0"
7
- gem "rspec", "~> 3.0"
6
+ gem 'rake', '~> 12.0'
7
+ gem 'rspec', '~> 3.0'
8
+
9
+ group :development do
10
+ gem 'rubocop'
11
+ gem 'rubocop-gitlab-security'
12
+ gem 'rubocop-performance'
13
+ gem 'rubocop-rails'
14
+ gem 'rubocop-rspec' # or gem 'rubocop-minitest'
15
+
16
+ gem 'solargraph'
17
+ end
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- xsdk-scaffold-rails (0.1.4.3)
4
+ xsdk-scaffold-rails (0.1.7)
5
5
  activerecord (>= 6.0.0)
6
6
  pg (>= 1.1)
7
7
 
@@ -20,18 +20,36 @@ GEM
20
20
  tzinfo (~> 1.1)
21
21
  zeitwerk (~> 2.2, >= 2.2.2)
22
22
  ast (2.4.2)
23
+ backport (1.1.2)
24
+ benchmark (0.1.1)
23
25
  concurrent-ruby (1.1.8)
24
26
  diff-lcs (1.4.4)
27
+ e2mmap (0.1.0)
25
28
  i18n (1.8.10)
26
29
  concurrent-ruby (~> 1.0)
30
+ jaro_winkler (1.5.4)
31
+ kramdown (2.3.1)
32
+ rexml
33
+ kramdown-parser-gfm (1.1.0)
34
+ kramdown (~> 2.0)
35
+ mini_portile2 (2.5.1)
27
36
  minitest (5.14.4)
37
+ nokogiri (1.11.5)
38
+ mini_portile2 (~> 2.5.0)
39
+ racc (~> 1.4)
40
+ nokogiri (1.11.5-x86_64-darwin)
41
+ racc (~> 1.4)
28
42
  parallel (1.20.1)
29
43
  parser (3.0.1.1)
30
44
  ast (~> 2.4.1)
31
45
  pg (1.2.3)
46
+ racc (1.5.2)
47
+ rack (2.2.3)
32
48
  rainbow (3.0.0)
33
49
  rake (12.3.3)
34
50
  regexp_parser (2.1.1)
51
+ reverse_markdown (2.0.0)
52
+ nokogiri
35
53
  rexml (3.2.5)
36
54
  rspec (3.10.0)
37
55
  rspec-core (~> 3.10.0)
@@ -57,17 +75,40 @@ GEM
57
75
  unicode-display_width (>= 1.4.0, < 2.0)
58
76
  rubocop-ast (1.5.0)
59
77
  parser (>= 3.0.1.1)
78
+ rubocop-gitlab-security (0.1.1)
79
+ rubocop (>= 0.51)
60
80
  rubocop-performance (1.9.2)
61
81
  rubocop (>= 0.90.0, < 2.0)
62
82
  rubocop-ast (>= 0.4.0)
83
+ rubocop-rails (2.9.1)
84
+ activesupport (>= 4.2.0)
85
+ rack (>= 1.1)
86
+ rubocop (>= 0.90.0, < 2.0)
63
87
  rubocop-rspec (2.0.1)
64
88
  rubocop (~> 1.0)
65
89
  rubocop-ast (>= 1.1.0)
66
90
  ruby-progressbar (1.11.0)
91
+ solargraph (0.40.4)
92
+ backport (~> 1.1)
93
+ benchmark
94
+ bundler (>= 1.17.2)
95
+ e2mmap
96
+ jaro_winkler (~> 1.5)
97
+ kramdown (~> 2.3)
98
+ kramdown-parser-gfm (~> 1.1)
99
+ parser (~> 3.0)
100
+ reverse_markdown (>= 1.0.5, < 3)
101
+ rubocop (>= 0.52)
102
+ thor (~> 1.0)
103
+ tilt (~> 2.0)
104
+ yard (~> 0.9, >= 0.9.24)
105
+ thor (1.1.0)
67
106
  thread_safe (0.3.6)
107
+ tilt (2.0.10)
68
108
  tzinfo (1.2.9)
69
109
  thread_safe (~> 0.1)
70
110
  unicode-display_width (1.7.0)
111
+ yard (0.9.26)
71
112
  zeitwerk (2.4.2)
72
113
 
73
114
  PLATFORMS
@@ -77,9 +118,12 @@ PLATFORMS
77
118
  DEPENDENCIES
78
119
  rake (~> 12.0)
79
120
  rspec (~> 3.0)
80
- rubocop (~> 1.3.1)
81
- rubocop-performance (~> 1.9.0)
82
- rubocop-rspec (~> 2.0.0)
121
+ rubocop
122
+ rubocop-gitlab-security
123
+ rubocop-performance
124
+ rubocop-rails
125
+ rubocop-rspec
126
+ solargraph
83
127
  xsdk-scaffold-rails!
84
128
 
85
129
  BUNDLED WITH
@@ -1,221 +1,282 @@
1
1
  module Xsdk
2
2
  module Scaffold
3
3
  module Rails
4
-
5
- class BaseDatatable
6
-
7
- def initialize(params, clazz)
8
- @options = JSON.parse(params[:options]).with_indifferent_access
9
- @clazz = clazz
10
- @foreign_keys = get_foreign_key_map(clazz)
11
- end
12
-
13
- def as_json(*)
14
- {
15
- rows: paginate(get_data),
16
- total_rows: get_count,
17
- columns: build_headers
18
- }
19
- end
20
-
21
- # Build rows
22
-
23
- def paginate(data)
24
- per_page = @options[:itemsPerPage]
25
- page = @options[:page] - 1
26
- data.limit(per_page)
27
- .offset(page * per_page)
28
- .as_json(methods: enum_methods, except: keys_to_exclude, include: has_many_include)
29
- end
30
-
31
- def keys_to_exclude
32
- []
33
- end
34
-
35
- def enum_methods
36
- enum_methods = []
37
- @clazz.defined_enums.each do |k, _v|
38
- enum_methods << "#{k}_text"
39
- end
40
- enum_methods
41
- end
42
-
43
- def get_raw_data
44
- @clazz.all
45
- end
46
-
47
- def get_data
48
- data = get_raw_data
49
- associations.reject { |_k, v| v[:association_type] == :has_many }.each do |_, value|
50
- data = data.joins(value[:relation])
51
- end
52
- to_select = associations.reject do |_k, v|
53
- v[:association_type] == :has_many
54
- end.reject { |_k, v| v[:source] == 'id' }.map do |key, value|
55
- table_name = @foreign_keys[key][0][:class_name].constantize.table_name
56
- "#{table_name}.#{value[:source]} AS #{value[:relation]}_#{value[:source]}"
57
- end
58
- data = data.select("#{@clazz.to_s.underscore.pluralize}.*", *to_select)
59
-
60
- associations.select { |_k, v| v[:association_type] == :has_many }.each do |_, v|
61
- data = data.includes(v[:join]).references(v[:join])
62
- end
63
-
64
- data
65
- end
66
-
67
- def has_many_include
68
- associations.select { |_, v| v[:association_type] == :has_many }.map { |_, v| v[:include] }
69
- end
70
-
71
- # Build columns
72
- def build_headers
73
- headers = columns.map do |c|
74
- {
75
- value: c, # warehouse_id
76
- table_value: get_table_value(c), # "mag1"
77
- text: get_text(c), # "Identificatore"
78
- type: get_type(c), # "string"
79
- in_form: form_columns.include?(c), # true/false
80
- in_table: table_columns.include?(c), # true/false
81
- table: get_table(c), # warehouses
82
- source: get_source(c), # identifier
83
- min_search_size: get_min_search_size(c),
84
- enum_cols: get_enum_cols(c),
85
- subschema: get_subschema(c)
86
- }
87
- end
88
- headers << { text: 'Azioni', value: 'actions', type: '', in_form: false, in_table: true }
89
- headers
90
- end
91
-
92
- def get_subschema(c)
93
- subschema = nil
94
- ax = associations.with_indifferent_access
95
- if ax.key?(c) && (ax[c][:association_type] == :has_many)
96
- empty_options = { options: '{}' }
97
- begin
98
- datatable = "#{ax[c][:clazz]}Datatable".constantize
99
- dt = datatable.new(empty_options)
100
- rescue StandardError
101
- dt = BaseDatatable.new(empty_options, ax[c][:clazz])
102
- end
103
- subschema = dt.build_headers
104
- subschema = subschema.reject { |c| c[:type] == 'foreign_key' && c[:table] == @clazz.table_name }
105
- subschema << { text: 'Elimina', value: '_destroy', type: '', in_form: false, in_table: false }
106
- subschema << { text: 'Uuid', value: '_uuid', type: 'uuid', in_form: false, in_table: false }
107
- subschema.each { |s| s[:is_subschema] = true }
108
- end
109
- subschema
110
- end
111
-
112
- def get_enum_cols(c)
113
- arr = []
114
- if @clazz.defined_enums.key?(c)
115
- @clazz.defined_enums[c].each do |k, _v|
116
- arr << {
117
- value: k,
118
- text: @clazz.human_attribute_name("#{c}_enum.#{k}")
119
- }
120
- end
121
- end
122
- arr
123
- end
124
-
125
- def get_min_search_size(c)
126
- ax = associations.with_indifferent_access
127
- if ax.key?(c) && ax[c][:source] == 'id'
128
- ax[c][:min_search_size]
129
- else
130
- 3
131
- end
132
- end
133
-
134
- def columns
135
- @clazz.column_names - %w[created_at updated_at]
136
- end
137
-
138
- def table_columns
139
- columns
140
- end
141
-
142
- def form_columns
143
- columns - ['id']
144
- end
145
-
146
- def get_table(c)
147
- ax = associations.with_indifferent_access
148
- if @foreign_keys.key?(c)
149
- @foreign_keys[c][0][:class_name].constantize.table_name
150
- elsif ax.key?(c) && (ax[c][:association_type] == :has_many)
151
- ax[c][:clazz].table_name
152
- else
153
- @clazz.table_name
154
- end
155
- end
156
-
157
- def get_source(c)
158
- ax = associations.with_indifferent_access
159
- if ax.key?(c) && (ax[c][:association_type] != :has_many)
160
- ax[c][:source]
161
- else
162
- c
163
- end
164
- end
165
-
166
- def get_text(c)
167
- ax = associations.with_indifferent_access
168
- if @foreign_keys.key?(c)
169
- @foreign_keys[c][0][:class_name].constantize.model_name.human.capitalize
170
- elsif ax.key?(c) && (ax[c][:association_type] == :has_many)
171
- ax[c][:clazz].model_name.human.capitalize
172
- else
173
- @clazz.human_attribute_name(c).capitalize
174
- end
175
- end
176
-
177
- def get_type(c)
178
- ax = associations.with_indifferent_access
179
- if @foreign_keys.key?(c)
180
- 'foreign_key'
181
- elsif ax.key?(c) && (ax[c][:association_type] == :has_many)
182
- 'has_many'
183
- elsif @clazz.defined_enums.key?(c)
184
- 'enum'
185
- else
186
- @clazz.type_for_attribute(c).type
187
- end
188
- end
189
-
190
- def get_table_value(c)
191
- ax = associations.with_indifferent_access
192
- if ax.key?(c)
193
- if ax[c][:association_type] == :has_many
194
- c
195
- else
196
- "#{ax[c][:relation]}_#{ax[c][:source]}"
197
- end
198
- else
199
- c
200
- end
201
- end
202
-
203
- def get_count
204
- @clazz.count
205
- end
206
-
207
- def get_foreign_key_map(clazz)
208
- clazz.reflect_on_all_associations.select { |a| a.macro == :belongs_to }
209
- .map { |a| { key: a.foreign_key, class_name: a.class_name } }
210
- .group_by { |a| a[:key] }
211
- .with_indifferent_access
212
- end
213
-
214
- def associations
215
- {}
216
- end
217
- end
4
+ class BaseDatatable
5
+ def initialize(params, clazz)
6
+ @options = JSON.parse(params[:options]).with_indifferent_access
7
+ @clazz = clazz
8
+ @foreign_keys = get_foreign_key_map(clazz)
9
+ @only_schema = @options[:only_schema]
10
+ @default_values = @options.try(:[], :default) || {}
11
+ end
218
12
 
13
+ def as_json(*)
14
+ return { columns: build_headers } if @only_schema
15
+
16
+ {
17
+ rows: paginate(get_data),
18
+ total_rows: get_count,
19
+ columns: build_headers
20
+ }
21
+ end
22
+
23
+ # Build rows
24
+
25
+ def paginate(data)
26
+ per_page = @options[:itemsPerPage]
27
+ page = @options[:page] - 1
28
+ sort = @options[:sortBy]
29
+ direction = @options[:sortDesc]
30
+ order_string = sort.map.with_index { |k, idx| "#{sorting_map[k.to_sym]} #{direction[idx] ? 'DESC' : 'ASC'}" }
31
+ data.limit(per_page)
32
+ .offset(page * per_page)
33
+ .order(order_string)
34
+ .as_json(methods: methods + enum_methods, except: keys_to_exclude, include: has_many_include)
35
+ end
36
+
37
+ def keys_to_exclude
38
+ []
39
+ end
40
+
41
+ def enum_methods
42
+ enum_methods = []
43
+ @clazz.defined_enums.each do |k, _v|
44
+ enum_methods << "#{k}_text"
45
+ end
46
+ enum_methods
47
+ end
48
+
49
+ def get_raw_data
50
+ @clazz.all
51
+ end
52
+
53
+ def get_data
54
+ data = get_raw_data
55
+ associations.reject { |_k, v| v[:association_type] == :has_many }.each do |_, value|
56
+ data = data.send(value[:join_type] || :joins, value[:relation])
57
+ end
58
+ to_select = associations.reject do |_k, v|
59
+ v[:association_type] == :has_many
60
+ end.reject { |_k, v| v[:source] == 'id' }.map do |key, value|
61
+ table_name = @foreign_keys[key][0][:class_name].constantize.table_name
62
+ "#{table_name}.#{value[:source]} AS #{value[:relation]}_#{value[:source]}"
63
+ end
64
+ data = data.select("#{@clazz.to_s.underscore.pluralize}.*", *to_select)
65
+
66
+ associations.select { |_k, v| v[:association_type] == :has_many }.each do |_, v|
67
+ data = data.includes(v[:join]).references(v[:join])
68
+ end
69
+
70
+ data
71
+ end
72
+
73
+ def has_many_include
74
+ associations.select { |_, v| v[:association_type] == :has_many }.map { |_, v| v[:include] }
75
+ end
76
+
77
+ def get_if_can_show_new_record(key)
78
+ key = key.to_sym
79
+ (associations.select { |k, v| k == key && v[:show_new_record] }).any?
80
+ end
81
+
82
+ def get_entity_name(key)
83
+ key = key.to_sym
84
+ assoc = associations[key]
85
+ return nil if assoc.nil?
86
+
87
+ assoc[:relation]
88
+ end
89
+
90
+ # Build columns
91
+ def build_headers
92
+ headers = columns.map do |c|
93
+ {
94
+ value: c, # warehouse_id
95
+ table_value: get_table_value(c), # "mag1"
96
+ text: get_text(c), # "Identificatore"
97
+ type: get_type(c), # "string"
98
+ in_form: get_in_form(c), # true/false
99
+ in_table: table_columns.include?(c), # true/false
100
+ table: get_table(c), # warehouses
101
+ source: get_source(c), # identifier
102
+ in_form_disabled: disabled_form_columns.include?(c), # true/false
103
+ min_search_size: get_min_search_size(c),
104
+ enum_cols: get_enum_cols(c),
105
+ subschema: get_subschema(c),
106
+ show_new_record: get_if_can_show_new_record(c),
107
+ entity_name: get_entity_name(c),
108
+ default: get_default_value(c)
109
+ }
110
+ end
111
+ headers << { text: 'Azioni', value: 'actions', type: '', in_form: false, in_table: true }
112
+ headers
113
+ end
114
+
115
+ def get_in_form(key)
116
+ (@options[:form_columns] || form_columns).include?(key)
117
+ end
118
+
119
+ def get_subschema(c)
120
+ subschema = nil
121
+ ax = associations.with_indifferent_access
122
+ if ax.key?(c) && (ax[c][:association_type] == :has_many)
123
+ child_options = { options: {}.to_json }
124
+ child_options = { options: ax[c][:options].to_json } if ax[c][:options].present?
125
+ begin
126
+ datatable = "#{ax[c][:clazz]}Datatable".constantize
127
+ dt = datatable.new(child_options)
128
+ rescue StandardError
129
+ dt = BaseDatatable.new(child_options, ax[c][:clazz])
130
+ end
131
+ subschema = dt.build_headers
132
+ subschema = subschema.reject { |sc| sc[:type] == 'foreign_key' && sc[:table] == @clazz.table_name }
133
+ subschema << { text: 'Elimina', value: '_destroy', type: '', in_form: false, in_table: false }
134
+ subschema << { text: 'Uuid', value: '_uuid', type: 'uuid', in_form: false, in_table: false }
135
+ subschema.each { |s| s[:is_subschema] = true }
136
+ end
137
+ subschema
138
+ end
139
+
140
+ def get_default_value(c)
141
+ @default_values[c]
142
+ end
143
+
144
+ def get_enum_cols(c)
145
+ arr = []
146
+ if @clazz.defined_enums.key?(c)
147
+ @clazz.defined_enums[c].each do |k, _v|
148
+ arr << {
149
+ value: k,
150
+ text: @clazz.human_attribute_name("#{c}_enum.#{k}")
151
+ }
152
+ end
153
+ end
154
+ arr
155
+ end
156
+
157
+ def get_min_search_size(c)
158
+ ax = associations.with_indifferent_access
159
+ if ax.key?(c) && ax[c][:source] == 'id'
160
+ ax[c][:min_search_size]
161
+ else
162
+ 3
163
+ end
164
+ end
165
+
166
+ def transient_columns
167
+ @options[:transient_columns] || {}
168
+ end
169
+
170
+ def columns
171
+ @clazz.column_names - %w[created_at updated_at] + transient_columns.keys
172
+ end
173
+
174
+ def table_columns
175
+ columns
176
+ end
177
+
178
+ def form_columns
179
+ columns - ['id']
180
+ end
181
+
182
+ def disabled_form_columns
183
+ []
184
+ end
185
+
186
+ def methods
187
+ []
188
+ end
189
+
190
+ def get_table(c)
191
+ ax = associations.with_indifferent_access
192
+ if @foreign_keys.key?(c)
193
+ @foreign_keys[c][0][:class_name].constantize.table_name
194
+ elsif ax.key?(c) && (ax[c][:association_type] == :has_many)
195
+ ax[c][:clazz].table_name
196
+ else
197
+ @clazz.table_name
198
+ end
199
+ end
200
+
201
+ def get_source(c)
202
+ ax = associations.with_indifferent_access
203
+ if ax.key?(c) && (ax[c][:association_type] != :has_many)
204
+ ax[c][:source]
205
+ else
206
+ c
207
+ end
208
+ end
209
+
210
+ def get_text(c)
211
+ ax = associations.with_indifferent_access
212
+ if @foreign_keys.key?(c)
213
+ @foreign_keys[c][0][:class_name].constantize.model_name.human.capitalize
214
+ elsif ax.key?(c) && (ax[c][:association_type] == :has_many)
215
+ ax[c][:clazz].model_name.human.capitalize
216
+ elsif transient_columns.key?(c)
217
+ transient_columns[c][:text]
218
+ else
219
+ @clazz.human_attribute_name(c).capitalize
220
+ end
221
+ end
222
+
223
+ def get_type(c)
224
+ ax = associations.with_indifferent_access
225
+ if @foreign_keys.key?(c)
226
+ 'foreign_key'
227
+ elsif ax.key?(c) && (ax[c][:association_type] == :has_many)
228
+ 'has_many'
229
+ elsif @clazz.defined_enums.key?(c)
230
+ 'enum'
231
+ elsif transient_columns.key?(c)
232
+ transient_columns[c][:type]
233
+ else
234
+ @clazz.type_for_attribute(c).type
235
+ end
236
+ end
237
+
238
+ def get_table_value(c)
239
+ ax = associations.with_indifferent_access
240
+ if ax.key?(c)
241
+ if ax[c][:association_type] == :has_many
242
+ c
243
+ else
244
+ "#{ax[c][:relation]}_#{ax[c][:source]}"
245
+ end
246
+ else
247
+ c
248
+ end
249
+ end
250
+
251
+ def get_count
252
+ @clazz.count
253
+ end
254
+
255
+ def get_foreign_key_map(clazz)
256
+ clazz.reflect_on_all_associations.select { |a| a.macro == :belongs_to }
257
+ .map { |a| { key: a.foreign_key, class_name: a.class_name } }
258
+ .group_by { |a| a[:key] }
259
+ .with_indifferent_access
260
+ end
261
+
262
+ def associations
263
+ {}
264
+ end
265
+
266
+ def sorting_map
267
+ build_headers.map do |h|
268
+ if h[:type] == 'foreign_key'
269
+ [h[:value].to_sym, "#{h[:table]}.#{h[:source]}"]
270
+ elsif h[:type] == 'enum'
271
+ ["#{h[:value]}_text".to_sym, "#{h[:table]}.#{h[:table_value]}"]
272
+ elsif h[:type].nil? || h[:value] == 'actions'
273
+ [nil]
274
+ else
275
+ [h[:value].to_sym, "#{h[:table]}.#{h[:table_value]}"]
276
+ end
277
+ end.filter { |a| a[0] }.to_h
278
+ end
279
+ end
219
280
  end
220
281
  end
221
282
  end
@@ -1,7 +1,7 @@
1
1
  module Xsdk
2
2
  module Scaffold
3
3
  module Rails
4
- VERSION = "0.1.4.3"
4
+ VERSION = "0.1.8"
5
5
  end
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xsdk-scaffold-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4.3
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Davide Croci
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-19 00:00:00.000000000 Z
11
+ date: 2021-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -124,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
126
  requirements: []
127
- rubygems_version: 3.0.8
127
+ rubygems_version: 3.2.3
128
128
  signing_key:
129
129
  specification_version: 4
130
130
  summary: Gem for automatic scaffolding by Ermes-x.