glib-web 4.39.0 → 4.39.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 +4 -4
- data/app/controllers/concerns/glib/auth/policy.rb +13 -0
- data/app/views/json_ui/garage/actions/_dialogs.json.jbuilder +2 -2
- data/app/views/json_ui/garage/forms/dynamic_group.json.jbuilder +2 -2
- data/app/views/json_ui/garage/forms/file_upload_new.json.jbuilder +1 -1
- data/app/views/json_ui/garage/forms/partial_update.json.jbuilder +12 -12
- data/app/views/json_ui/garage/forms/selects.json.jbuilder +1 -1
- data/app/views/json_ui/garage/forms/show_hide.json.jbuilder +62 -7
- data/app/views/json_ui/garage/lists/edit_mode.json.jbuilder +4 -4
- data/app/views/json_ui/garage/pages/custom_style_class.json.jbuilder +1 -1
- data/app/views/json_ui/garage/pages/nav_buttons.json.jbuilder +31 -13
- data/app/views/json_ui/garage/panels/_styled.json.jbuilder +8 -8
- data/app/views/json_ui/garage/panels/hover.json.jbuilder +2 -2
- data/app/views/json_ui/garage/panels/timeline.json.jbuilder +5 -5
- data/app/views/json_ui/garage/panels/ul.json.jbuilder +1 -1
- data/app/views/json_ui/garage/tables/bulk_edit.json.jbuilder +1 -1
- data/app/views/json_ui/garage/test_page/file_upload_new.json.jbuilder +1 -1
- data/app/views/json_ui/garage/test_page/form.json.jbuilder +6 -6
- data/app/views/json_ui/garage/test_page/form_dynamic.json.jbuilder +2 -2
- data/app/views/json_ui/garage/test_page/logics_set.json.jbuilder +94 -0
- data/app/views/json_ui/garage/views/components_replace.json.jbuilder +13 -13
- data/app/views/json_ui/garage/views/components_set.json.jbuilder +6 -6
- data/app/views/json_ui/garage/views/fields_focus.json.jbuilder +22 -22
- data/lib/glib/json_crawler/router.rb +45 -24
- data/lib/glib/rubocop/cops/json_ui/base_nested_parameter.rb +145 -0
- data/lib/glib/rubocop/cops/json_ui/nested_action_parameter.rb +55 -0
- data/lib/glib/rubocop/cops/json_ui/nested_block_parameter.rb +51 -0
- data/lib/glib/rubocop/cops/multiline_method_call_style.rb +74 -5
- data/lib/glib/rubocop.rb +3 -0
- data/lib/glib/test/parallel_coverage.rb +38 -0
- data/lib/glib/test_helpers.rb +12 -0
- data/lib/glib-web.rb +1 -0
- metadata +6 -1
|
@@ -11,44 +11,44 @@ page.body padding: glib_json_padding_body, childViews: ->(body) do
|
|
|
11
11
|
method: 'post',
|
|
12
12
|
width: 300,
|
|
13
13
|
childViews: ->(form) do
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
14
|
+
form.fields_text id: 'first', name: 'user[full_name]', label: 'Full name', placeholder: 'Full name', width: 'matchParent'
|
|
15
|
+
form.spacer height: 4
|
|
16
|
+
form.fields_number id: 'second', name: 'user[age]', label: 'Age', placeholder: 'Age', width: 'matchParent'
|
|
17
|
+
form.spacer height: 4
|
|
18
|
+
form.fields_textarea id: 'third', name: 'user[boi]', label: 'Bio', placeholder: 'Bio', width: 'matchParent'
|
|
19
|
+
form.spacer height: 4
|
|
20
|
+
form.fields_date id: 'fourth', name: 'user[birth_date]', label: 'Birth date', placeholder: 'Birth date', width: 'matchParent'
|
|
21
|
+
form.spacer height: 4
|
|
22
|
+
form.panels_horizontal childViews: ->(hori) do
|
|
23
|
+
hori.button text: 'focus1', onClick: ->(action) do
|
|
24
24
|
action.fields_focus targetId: 'first'
|
|
25
25
|
end
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
hori.spacer width: 4
|
|
27
|
+
hori.button text: 'focus2', onClick: ->(action) do
|
|
28
28
|
action.fields_focus targetId: 'second'
|
|
29
29
|
end
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
hori.spacer width: 4
|
|
31
|
+
hori.button text: 'focus3', onClick: ->(action) do
|
|
32
32
|
action.fields_focus targetId: 'third'
|
|
33
33
|
end
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
hori.spacer width: 4
|
|
35
|
+
hori.button text: 'focus4', onClick: ->(action) do
|
|
36
36
|
action.fields_focus targetId: 'fourth'
|
|
37
37
|
end
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
hori.spacer width: 4
|
|
39
|
+
hori.button text: 'blur', onClick: ->(action) do
|
|
40
40
|
action.fields_focus targetId: 'first', onFocus: ->(saction) do
|
|
41
41
|
saction.timeouts_set interval: 1000, onTimeout: ->(ssaction) { ssaction.fields_blur }
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
hori.spacer width: 4
|
|
45
|
+
hori.button text: 'reset', onClick: ->(action) do
|
|
46
46
|
action.fields_reset targetIds: ['first', 'second', 'third', 'fourth'], onReset: ->(saction) do
|
|
47
47
|
saction.snackbars_alert styleClasses: ['success'], message: 'Reset full name!'
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
hori.spacer width: 4
|
|
51
|
+
hori.fields_submit text: 'submit'
|
|
52
52
|
end
|
|
53
53
|
end
|
|
54
54
|
|
|
@@ -8,20 +8,20 @@ module Glib
|
|
|
8
8
|
attr_reader :http_actions
|
|
9
9
|
attr_accessor :host, :skip_similar_page
|
|
10
10
|
|
|
11
|
-
def log(action,
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
def log(action, key_data, response = nil)
|
|
12
|
+
# Sometimes `key_data` may not be an actual URL, e.g. in the context of dialogs_alert,
|
|
13
|
+
# it is the alert message.
|
|
14
|
+
if key_data&.start_with?('http://', 'https://')
|
|
15
|
+
key_data = remove_params(key_data, [:__glib_permission_test])
|
|
14
16
|
end
|
|
15
17
|
|
|
16
18
|
@last_log = [
|
|
17
19
|
action,
|
|
18
20
|
response.present? ? response.code : nil,
|
|
19
|
-
|
|
21
|
+
key_data
|
|
20
22
|
].compact.join(
|
|
21
23
|
' :: '
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
# puts @last_log
|
|
24
|
+
)
|
|
25
25
|
|
|
26
26
|
@logger += ' ' * @depth + @last_log + "\n"
|
|
27
27
|
end
|
|
@@ -172,24 +172,27 @@ module Glib
|
|
|
172
172
|
crawler_actions.each do |crawler_action|
|
|
173
173
|
action, url, params = crawler_action
|
|
174
174
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
http.delete(url, action, params)
|
|
175
|
+
# In full mode, wrap each action in a transaction that gets rolled back
|
|
176
|
+
# to ensure database state is reset between each URL check (prevent database contamination)
|
|
177
|
+
if ENV['GLIB_DISABLE_PERMISSION_TEST_SKIP'] == 'true'
|
|
178
|
+
# This solution is important for permissions tests (not as much in the crawler tests),
|
|
179
|
+
# because in permission tests, the user hits every single available URLs with a single purpose
|
|
180
|
+
# of checking the permission of every URL, meaning that one incorrect result (e.g. 403 instead of 200 due to
|
|
181
|
+
# side effect from previous URL requests) cannot be tolerated.
|
|
182
|
+
#
|
|
183
|
+
# On the other hand, crawler tests are expected to cover only one scenario anyway, so
|
|
184
|
+
# having the scenario changed (due to side effects) is fine. We decided it's better not
|
|
185
|
+
# to apply this solution for crawler tests out of performance considerations.
|
|
186
|
+
ActiveRecord::Base.transaction do
|
|
187
|
+
execute_crawler_action(http, action, url, params)
|
|
188
|
+
raise ActiveRecord::Rollback
|
|
189
|
+
end
|
|
191
190
|
else
|
|
192
|
-
|
|
191
|
+
# In skip mode, add the permission test parameter
|
|
192
|
+
if url.present?
|
|
193
|
+
url = add_params(url, __glib_permission_test: true)
|
|
194
|
+
end
|
|
195
|
+
execute_crawler_action(http, action, url, params)
|
|
193
196
|
end
|
|
194
197
|
end
|
|
195
198
|
end
|
|
@@ -224,6 +227,24 @@ module Glib
|
|
|
224
227
|
end
|
|
225
228
|
|
|
226
229
|
private
|
|
230
|
+
def execute_crawler_action(http, action, url, params)
|
|
231
|
+
params = JSON.parse(params) if params.is_a?(String)
|
|
232
|
+
params ||= {}
|
|
233
|
+
|
|
234
|
+
case action.to_s.downcase
|
|
235
|
+
when 'http/post-v1', 'forms/post'
|
|
236
|
+
http.post(url, action, params)
|
|
237
|
+
when 'http/patch-v1', 'forms/patch'
|
|
238
|
+
http.patch(url, action, params)
|
|
239
|
+
when 'http/put-v1', 'forms/put'
|
|
240
|
+
http.put(url, action, params)
|
|
241
|
+
when 'http/delete-v1'
|
|
242
|
+
http.delete(url, action, params)
|
|
243
|
+
else
|
|
244
|
+
http.get(url, action, params)
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
227
248
|
def add_params(url, new_params)
|
|
228
249
|
uri = URI(url)
|
|
229
250
|
existing = URI.decode_www_form(uri.query || '')
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Glib
|
|
6
|
+
module JsonUi
|
|
7
|
+
# Base class for checking nested block parameter violations in JsonUi templates.
|
|
8
|
+
# Handles both parameter shadowing and incorrect usage of outer variables.
|
|
9
|
+
class BaseNestedParameter < Base
|
|
10
|
+
extend AutoCorrector
|
|
11
|
+
|
|
12
|
+
MSG_OUTER_VAR = 'Use the immediate block parameter `%<immediate>s` instead of outer variable `%<outer>s`.'
|
|
13
|
+
|
|
14
|
+
def on_block(node)
|
|
15
|
+
check_nested_block(node)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
alias on_numblock on_block
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def check_nested_block(node)
|
|
23
|
+
block_param = extract_block_param(node)
|
|
24
|
+
return unless block_param
|
|
25
|
+
return unless relevant_block?(node)
|
|
26
|
+
|
|
27
|
+
parent_blocks = find_parent_relevant_blocks(node)
|
|
28
|
+
return if parent_blocks.empty?
|
|
29
|
+
|
|
30
|
+
parent_params = parent_blocks.filter_map { |b| extract_block_param(b) }
|
|
31
|
+
|
|
32
|
+
# Check for parameter shadowing
|
|
33
|
+
check_shadowing(node, block_param, parent_params)
|
|
34
|
+
|
|
35
|
+
# Check for incorrect usage of outer variables
|
|
36
|
+
check_send_nodes_in_body(node.body, block_param, parent_params)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def check_shadowing(node, block_param, parent_params)
|
|
40
|
+
parent_params.each do |parent_param|
|
|
41
|
+
next unless block_param == parent_param
|
|
42
|
+
|
|
43
|
+
param_node = node.arguments.children.first
|
|
44
|
+
suggested_name = suggest_param_name(parent_param)
|
|
45
|
+
|
|
46
|
+
add_offense(
|
|
47
|
+
param_node,
|
|
48
|
+
message: shadowing_message(parent_param, suggested_name)
|
|
49
|
+
) do |corrector|
|
|
50
|
+
corrector.replace(param_node, suggested_name)
|
|
51
|
+
replace_param_usages(corrector, node.body, parent_param, suggested_name)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def check_send_nodes_in_body(body_node, current_param, parent_params)
|
|
57
|
+
return unless body_node
|
|
58
|
+
|
|
59
|
+
body_node.each_child_node do |child|
|
|
60
|
+
if child.send_type? || child.csend_type?
|
|
61
|
+
check_send_node(child, current_param, parent_params)
|
|
62
|
+
elsif !child.block_type? && !child.numblock_type?
|
|
63
|
+
# Recurse into non-block nodes
|
|
64
|
+
check_send_nodes_in_body(child, current_param, parent_params)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def check_send_node(send_node, current_param, parent_params)
|
|
70
|
+
receiver = send_node.receiver
|
|
71
|
+
return unless receiver&.lvar_type?
|
|
72
|
+
|
|
73
|
+
receiver_name = receiver.children.first
|
|
74
|
+
|
|
75
|
+
parent_params.each do |parent_param|
|
|
76
|
+
next unless receiver_name == parent_param.to_sym
|
|
77
|
+
|
|
78
|
+
add_offense(
|
|
79
|
+
receiver,
|
|
80
|
+
message: format(MSG_OUTER_VAR, immediate: current_param, outer: parent_param)
|
|
81
|
+
) do |corrector|
|
|
82
|
+
corrector.replace(receiver, current_param.to_s)
|
|
83
|
+
end
|
|
84
|
+
break
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def extract_block_param(node)
|
|
89
|
+
return nil unless node.block_type? || node.numblock_type?
|
|
90
|
+
return nil if node.numblock_type? # Numbered blocks not supported
|
|
91
|
+
|
|
92
|
+
args = node.arguments
|
|
93
|
+
return nil if args.children.empty?
|
|
94
|
+
|
|
95
|
+
args.children.first.children.first
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def find_parent_relevant_blocks(node)
|
|
99
|
+
blocks = []
|
|
100
|
+
current = node.parent
|
|
101
|
+
|
|
102
|
+
while current
|
|
103
|
+
if (current.block_type? || current.numblock_type?) && current != node
|
|
104
|
+
blocks << current if relevant_block?(current)
|
|
105
|
+
end
|
|
106
|
+
current = current.parent
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
blocks
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def lambda_block?(block_node)
|
|
113
|
+
block_node.block_type? && block_node.send_node.method_name == :lambda
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def hash_pair_parent(block_node)
|
|
117
|
+
current = block_node.parent
|
|
118
|
+
current if current&.pair_type?
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def replace_param_usages(corrector, body_node, old_name, new_name)
|
|
122
|
+
return unless body_node
|
|
123
|
+
|
|
124
|
+
body_node.each_descendant(:lvar) do |lvar_node|
|
|
125
|
+
corrector.replace(lvar_node, new_name) if lvar_node.children.first == old_name.to_sym
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def suggest_param_name(parent_param)
|
|
130
|
+
parent_param.to_s.start_with?('sub') ? "#{parent_param}2" : "sub#{parent_param}"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def shadowing_message(parent_param, suggested_name)
|
|
134
|
+
"Avoid shadowing the outer parameter `#{parent_param}`. Use a different name like `#{suggested_name}`."
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# To be implemented by subclasses
|
|
138
|
+
def relevant_block?(_block_node)
|
|
139
|
+
raise NotImplementedError, "#{self.class} must implement #relevant_block?"
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_nested_parameter'
|
|
4
|
+
|
|
5
|
+
module RuboCop
|
|
6
|
+
module Cop
|
|
7
|
+
module Glib
|
|
8
|
+
module JsonUi
|
|
9
|
+
# Enforces using the immediate block parameter instead of outer block variables
|
|
10
|
+
# in nested action blocks (onClick, onClose, onChange, etc.) in JsonUi templates.
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# # bad - parameter shadowing
|
|
14
|
+
# button onClick: ->(action) do
|
|
15
|
+
# action.dialogs_alert onClose: ->(action) do # shadows outer 'action'
|
|
16
|
+
# action.snackbars_alert message: 'Closed'
|
|
17
|
+
# end
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# # good
|
|
21
|
+
# button onClick: ->(action) do
|
|
22
|
+
# action.dialogs_alert onClose: ->(subaction) do
|
|
23
|
+
# subaction.snackbars_alert message: 'Closed'
|
|
24
|
+
# end
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# # bad - using outer variable
|
|
28
|
+
# button onClick: ->(action) do
|
|
29
|
+
# action.dialogs_alert onClose: ->(subaction) do
|
|
30
|
+
# action.forms_submit # using 'action' instead of 'subaction'
|
|
31
|
+
# end
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
# # good
|
|
35
|
+
# button onClick: ->(action) do
|
|
36
|
+
# action.dialogs_alert onClose: ->(subaction) do
|
|
37
|
+
# subaction.forms_submit
|
|
38
|
+
# end
|
|
39
|
+
# end
|
|
40
|
+
class NestedActionParameter < BaseNestedParameter
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def relevant_block?(block_node)
|
|
44
|
+
return false unless lambda_block?(block_node)
|
|
45
|
+
|
|
46
|
+
pair = hash_pair_parent(block_node)
|
|
47
|
+
return false unless pair
|
|
48
|
+
|
|
49
|
+
pair.key.sym_type? && pair.key.value.to_s.start_with?('on')
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_nested_parameter'
|
|
4
|
+
|
|
5
|
+
module RuboCop
|
|
6
|
+
module Cop
|
|
7
|
+
module Glib
|
|
8
|
+
module JsonUi
|
|
9
|
+
# Enforces using the immediate block parameter instead of outer block variables
|
|
10
|
+
# in nested view blocks (childViews, content) in JsonUi templates.
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# # bad - using outer variable
|
|
14
|
+
# scroll.panels_form childViews: ->(form) do
|
|
15
|
+
# scroll.label text: 'TEST' # using 'scroll' instead of 'form'
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# # good
|
|
19
|
+
# scroll.panels_form childViews: ->(form) do
|
|
20
|
+
# form.label text: 'TEST'
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# # bad - parameter shadowing
|
|
24
|
+
# scroll.panels_form childViews: ->(form) do
|
|
25
|
+
# form.panels_responsive childViews: ->(form) do # shadows outer 'form'
|
|
26
|
+
# form.fields_text name: 'user[field]'
|
|
27
|
+
# end
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# # good
|
|
31
|
+
# scroll.panels_form childViews: ->(form) do
|
|
32
|
+
# form.panels_responsive childViews: ->(res) do
|
|
33
|
+
# res.fields_text name: 'user[field]'
|
|
34
|
+
# end
|
|
35
|
+
# end
|
|
36
|
+
class NestedBlockParameter < BaseNestedParameter
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def relevant_block?(block_node)
|
|
40
|
+
return false unless lambda_block?(block_node)
|
|
41
|
+
|
|
42
|
+
pair = hash_pair_parent(block_node)
|
|
43
|
+
return false unless pair
|
|
44
|
+
|
|
45
|
+
pair.key.sym_type? && [:childViews, :content].include?(pair.key.value)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -37,6 +37,7 @@ module RuboCop
|
|
|
37
37
|
return unless multi_line_call_with_args?(node)
|
|
38
38
|
return if proper_parentheses_style?(node)
|
|
39
39
|
return if proper_backslash_style?(node) && allow_backslash?
|
|
40
|
+
return if inside_correctable_parent?(node)
|
|
40
41
|
|
|
41
42
|
add_offense(node) do |corrector|
|
|
42
43
|
autocorrect(corrector, node)
|
|
@@ -122,12 +123,28 @@ module RuboCop
|
|
|
122
123
|
args
|
|
123
124
|
end
|
|
124
125
|
|
|
126
|
+
def inside_correctable_parent?(node)
|
|
127
|
+
# Check if this node is inside a block that belongs to a multi-line call
|
|
128
|
+
# that will also be corrected. If so, skip this node to avoid conflicts.
|
|
129
|
+
current = node.parent
|
|
130
|
+
|
|
131
|
+
while current
|
|
132
|
+
if current.send_type? || current.csend_type?
|
|
133
|
+
if multi_line_call_with_args?(current) && !proper_parentheses_style?(current)
|
|
134
|
+
return true
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
current = current.parent
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
false
|
|
141
|
+
end
|
|
142
|
+
|
|
125
143
|
def autocorrect(corrector, node)
|
|
126
144
|
method_end_pos = node.loc.selector.end_pos
|
|
127
145
|
|
|
128
|
-
#
|
|
129
|
-
|
|
130
|
-
base_indent = node.source_range.begin_pos - line_begin_pos
|
|
146
|
+
# Calculate indentation based on the node's actual column position
|
|
147
|
+
base_indent = node.loc.column
|
|
131
148
|
arg_indent = ' ' * (base_indent + 2)
|
|
132
149
|
|
|
133
150
|
# Build the new argument list
|
|
@@ -137,7 +154,9 @@ module RuboCop
|
|
|
137
154
|
|
|
138
155
|
if arg.hash_type?
|
|
139
156
|
arg.pairs.each do |pair|
|
|
140
|
-
|
|
157
|
+
# Re-indent pair if it contains a block
|
|
158
|
+
pair_source = reindent_pair_with_block(pair, arg_indent)
|
|
159
|
+
arg_parts << pair_source
|
|
141
160
|
end
|
|
142
161
|
else
|
|
143
162
|
arg_parts << arg.source
|
|
@@ -151,7 +170,7 @@ module RuboCop
|
|
|
151
170
|
|
|
152
171
|
# If there's a block, add it on the last argument line
|
|
153
172
|
if node.block_literal?
|
|
154
|
-
block_source = node.block_literal
|
|
173
|
+
block_source = reindent_block(node.block_literal, arg_indent)
|
|
155
174
|
replacement += " #{block_source}"
|
|
156
175
|
end
|
|
157
176
|
|
|
@@ -175,6 +194,56 @@ module RuboCop
|
|
|
175
194
|
|
|
176
195
|
corrector.replace(range, replacement)
|
|
177
196
|
end
|
|
197
|
+
|
|
198
|
+
def reindent_pair_with_block(pair, base_indent)
|
|
199
|
+
# Check if the pair's value is a block
|
|
200
|
+
return pair.source unless pair.value.block_type?
|
|
201
|
+
|
|
202
|
+
# Format: "key: ->(param) do ... end"
|
|
203
|
+
key_source = pair.key.source
|
|
204
|
+
block_source = reindent_block(pair.value, base_indent)
|
|
205
|
+
|
|
206
|
+
"#{key_source}: #{block_source}"
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def reindent_block(block_node, base_indent)
|
|
210
|
+
# Get block source lines
|
|
211
|
+
source = block_node.source
|
|
212
|
+
lines = source.lines
|
|
213
|
+
|
|
214
|
+
return source if lines.length == 1 # Single line block, no reindent needed
|
|
215
|
+
|
|
216
|
+
# Find the current indentation of the block's first line
|
|
217
|
+
# (this is usually where "do" appears)
|
|
218
|
+
first_line = lines[0]
|
|
219
|
+
|
|
220
|
+
# Process the block:
|
|
221
|
+
# Line 0: "->(param) do" - keep as is
|
|
222
|
+
# Lines 1..-2: block body - re-indent to base_indent + 2
|
|
223
|
+
# Last line: "end" - indent to base_indent
|
|
224
|
+
|
|
225
|
+
result_lines = []
|
|
226
|
+
block_body_indent = base_indent + ' ' * 2
|
|
227
|
+
|
|
228
|
+
lines.each_with_index do |line, index|
|
|
229
|
+
if index == 0
|
|
230
|
+
# First line: "->(param) do"
|
|
231
|
+
result_lines << line.rstrip
|
|
232
|
+
elsif index == lines.length - 1
|
|
233
|
+
# Last line: "end"
|
|
234
|
+
result_lines << "#{base_indent}#{line.strip}"
|
|
235
|
+
else
|
|
236
|
+
# Body lines: re-indent
|
|
237
|
+
# Remove existing indentation and add new indentation
|
|
238
|
+
stripped = line.lstrip
|
|
239
|
+
next if stripped.empty? # Skip blank lines
|
|
240
|
+
|
|
241
|
+
result_lines << "#{block_body_indent}#{stripped.rstrip}"
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
result_lines.join("\n")
|
|
246
|
+
end
|
|
178
247
|
end
|
|
179
248
|
end
|
|
180
249
|
end
|
data/lib/glib/rubocop.rb
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
require_relative 'rubocop/cops/localize'
|
|
2
2
|
require_relative 'rubocop/cops/multiline_method_call_style'
|
|
3
|
+
require_relative 'rubocop/cops/json_ui/base_nested_parameter'
|
|
4
|
+
require_relative 'rubocop/cops/json_ui/nested_block_parameter'
|
|
5
|
+
require_relative 'rubocop/cops/json_ui/nested_action_parameter'
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Glib
|
|
4
|
+
module Test
|
|
5
|
+
# ParallelCoverage configures Rails parallel testing to work properly with SimpleCov.
|
|
6
|
+
#
|
|
7
|
+
# Without this configuration, SimpleCov reports inaccurate coverage (often very low, like 1-2%)
|
|
8
|
+
# when running tests with parallelization enabled, because it only captures data from one worker
|
|
9
|
+
# instead of merging results from all parallel workers.
|
|
10
|
+
#
|
|
11
|
+
# Usage:
|
|
12
|
+
# class ActiveSupport::TestCase
|
|
13
|
+
# include Glib::Test::ParallelCoverage
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# This will:
|
|
17
|
+
# - Enable parallel test execution using all available processors
|
|
18
|
+
# - Configure SimpleCov to track each worker separately
|
|
19
|
+
# - Automatically merge coverage results from all workers
|
|
20
|
+
module ParallelCoverage
|
|
21
|
+
extend ActiveSupport::Concern
|
|
22
|
+
|
|
23
|
+
included do
|
|
24
|
+
# Set threshold for force parallelization.
|
|
25
|
+
parallelize(workers: :number_of_processors, threshold: 1)
|
|
26
|
+
|
|
27
|
+
# Configure SimpleCov to properly merge coverage from parallel workers
|
|
28
|
+
parallelize_setup do |worker|
|
|
29
|
+
SimpleCov.command_name "#{SimpleCov.command_name}-#{worker}"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
parallelize_teardown do |_worker|
|
|
33
|
+
SimpleCov.result
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/glib/test_helpers.rb
CHANGED
|
@@ -83,6 +83,18 @@ module Glib
|
|
|
83
83
|
"http://#{HOST}/users/sign_out.json"
|
|
84
84
|
end
|
|
85
85
|
|
|
86
|
+
def glib_travel(*args, &block)
|
|
87
|
+
Timecop.travel(*args, &block)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def glib_travel_freeze(*args, &block)
|
|
91
|
+
Timecop.freeze(*args, &block)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def glib_travel_back
|
|
95
|
+
Timecop.return
|
|
96
|
+
end
|
|
97
|
+
|
|
86
98
|
private
|
|
87
99
|
def __execute_crawler(user, inspect_http:, log_file: nil, &block)
|
|
88
100
|
auth_token = login user
|
data/lib/glib-web.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: glib-web
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.39.
|
|
4
|
+
version: 4.39.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ''
|
|
@@ -376,6 +376,7 @@ files:
|
|
|
376
376
|
- app/views/json_ui/garage/test_page/form.json.jbuilder
|
|
377
377
|
- app/views/json_ui/garage/test_page/form_dynamic.json.jbuilder
|
|
378
378
|
- app/views/json_ui/garage/test_page/lifecycle.json.jbuilder
|
|
379
|
+
- app/views/json_ui/garage/test_page/logics_set.json.jbuilder
|
|
379
380
|
- app/views/json_ui/garage/test_page/multiupload.json.jbuilder
|
|
380
381
|
- app/views/json_ui/garage/test_page/selectable.json.jbuilder
|
|
381
382
|
- app/views/json_ui/garage/test_page/window.json.jbuilder
|
|
@@ -442,9 +443,13 @@ files:
|
|
|
442
443
|
- lib/glib/json_crawler/router.rb
|
|
443
444
|
- lib/glib/mailer_tester.rb
|
|
444
445
|
- lib/glib/rubocop.rb
|
|
446
|
+
- lib/glib/rubocop/cops/json_ui/base_nested_parameter.rb
|
|
447
|
+
- lib/glib/rubocop/cops/json_ui/nested_action_parameter.rb
|
|
448
|
+
- lib/glib/rubocop/cops/json_ui/nested_block_parameter.rb
|
|
445
449
|
- lib/glib/rubocop/cops/localize.rb
|
|
446
450
|
- lib/glib/rubocop/cops/multiline_method_call_style.rb
|
|
447
451
|
- lib/glib/snapshot.rb
|
|
452
|
+
- lib/glib/test/parallel_coverage.rb
|
|
448
453
|
- lib/glib/test_helpers.rb
|
|
449
454
|
- lib/glib/time_freezable_mailer.rb
|
|
450
455
|
- lib/glib/time_returning_mailer.rb
|