sqreen 1.5.0-java → 1.6.0-java

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
  SHA1:
3
- metadata.gz: 7dabc8645b6eaca59937e5742c95229b6a4016b4
4
- data.tar.gz: 0a9b782a69bd8b807d4bfc6077bad91b9e9b537f
3
+ metadata.gz: b6b96afe645e834947aa8a4ba899a0c94d9b8037
4
+ data.tar.gz: b09d59bff4ba050f2d3409c2896e7df6ba26c5b7
5
5
  SHA512:
6
- metadata.gz: 7d2f9dd053786379e7b8a2834bb4e73499c7a4d74ab1835710ea4341196b428b71759d905543e108eede149b1ea7ba2fb47ce8741a63424f019a43113f7708dd
7
- data.tar.gz: df8b05e55f77b2a34bdbcc89c5dbe0586fa476597c4784a20818418880bba75d43c3ee6176125f7594fccf9a26a9e3e8c1ff53b4947d63438757360267c3696f
6
+ metadata.gz: bf2acd08c3047ba024c7479859118cd5b4eeef937a5562184bb83c329bc60d266ccf35d6da7318e59d8b3fc79a0d33ec9fd0d888a37f3afc70306507cde7a700
7
+ data.tar.gz: b22575e52f4df22aea73f12bd1b719238fbcd7062c659f75d70c69c0c65a98112efca7c887b81847a74be27c76cc02d4afbe110ecb90be2c245eca90a1524efc
@@ -0,0 +1,2 @@
1
+ <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Sqreen has detected an attack.</title> <style>html,body,div,span,h1,a{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}body{background:-webkit-radial-gradient(26% 19%,circle,#fff,#f4f7f9);background:radial-gradient(circle at 26% 19%,#fff,#f4f7f9);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:center;align-content:center;width:100%;min-height:100vh;line-height:1}svg,h1,p{display:block}svg{margin:0 auto 4vh}h1{font-family:sans-serif;font-weight:300;font-size:34px;color:#384886;line-height:normal}p{font-size:18px;line-height:normal;color:#b8bccc;font-family:sans-serif;font-weight:300}a{color:#b8bccc}.flex{text-align:center}</style></head><body> <div class="flex"> <svg xmlns="http://www.w3.org/2000/svg" width="230" height="250" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <path id="b" d="M176.55 22.93v-.03c-.17-1.13-.8-2.1-1.9-2.77C170.93 18.07 136.8.03 88.98 0 40.25 0 4.8 19.28 3.28 20.14c-.98.6-1.63 1.6-1.77 2.72-14.8 123.1 84.7 176.2 85.7 176.7.6.3 1.2.44 1.8.44.6 0 1.2-.15 1.7-.42 1-.52 100.4-55.03 85.9-176.65z"/> <filter id="a" width="151.7%" height="146%" x="-25.8%" y="-16%" filterUnits="objectBoundingBox"> <feOffset dy="14" in="SourceAlpha" result="shadowOffsetOuter1"/> <feGaussianBlur stdDeviation="13" in="shadowOffsetOuter1" result="shadowBlurOuter1"/> <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" in="shadowBlurOuter1"/> </filter> </defs> <g fill="none" fill-rule="evenodd"> <g fill-rule="nonzero" transform="translate(26 12)"> <use fill="#000" filter="url(#a)" xlink:href="#b"/> <use fill="#FFF" fill-rule="evenodd" xlink:href="#b"/> </g> <path fill="#374886" d="M153.85 75.8s0 .68-.35 1.13c-.46.57-8.52 10.74-12.32 15.6-3.8 4.98-11.52 2.26-11.52 2.26s2.54-1.5 4.15-3.4c4.3-5.3 12.5-15.7 12.5-15.7s-8.2-10.2-12.4-15.6c-1.5-2-4.1-3.4-4.1-3.4s7.7-2.6 11.5 2.2c3.8 4.9 11.9 15.1 12.2 15.7.5.4.5 1.1.5 1.1m-78 .1s0 .6.4 1.1c.4.4 8.5 10.7 12.2 15.6 3.7 4.8 11.5 2.2 11.5 2.2s-2.5-1.5-4.1-3.4c-4.3-5.2-12.5-15.5-12.5-15.5l12.4-15.7c1.5-2 4.2-3.4 4.2-3.4s-7.7-2.6-11.5 2.2C84.8 63.7 76.9 74 76.5 74.6c-.32.55-.44 1.12-.44 1.12M115 62.82c-7.03 0-12.9 5.78-12.9 12.9s5.75 12.9 12.9 12.9c7.13 0 12.9-5.8 12.9-12.9s-5.9-12.9-12.9-12.9m-33.38 58.6c3.46 0 5.4-1.77 5.4-4.1 0-5.15-7.4-3.56-7.4-5.47 0-.8.78-1.3 1.97-1.3 1.5 0 2.9.6 3.7 1.5l1.3-2.3c-1.3-1-2.9-1.8-5.1-1.8-3.3 0-5.1 1.9-5.1 4 0 5 7.5 3.3 7.5 5.4 0 .8-.6 1.4-2.1 1.4s-3.4-.9-4.3-1.8l-1.4 2.4c1.4 1.2 3.4 2 5.6 2zm13.53-3c-1.8 0-3.1-1.5-3.1-3.7s1.3-3.7 3.2-3.7c1.1 0 2.3.6 2.8 1.44v4.5c-.5.8-1.7 1.46-2.8 1.46zm-1 3c1.5 0 2.9-.64 3.9-1.96v6.5h3.3v-17.63H98v1.6c-.96-1.23-2.33-1.92-3.86-1.92-3.2 0-5.52 2.5-5.52 6.7 0 4.3 2.33 6.7 5.53 6.7zm13.7-.32v-8.42c.6-.8 2-1.4 3.1-1.4.4 0 .7.1.9.1v-3.3c-1.5 0-3.1 1-3.9 2.1v-1.7h-3.3v12.8h3.3zm11.9.33c2 0 3.9-.6 5.2-1.77l-1.4-2.2c-.8.8-2.26 1.2-3.32 1.2-2.1 0-3.4-1.4-3.6-3h9.3v-.7c0-4.2-2.53-7.1-6.25-7.1-3.8 0-6.45 3-6.45 6.7 0 4.05 2.8 6.7 6.6 6.7zm2.9-7.9h-6.1c.2-1.27 1.07-2.83 3.1-2.83 2.18 0 3 1.6 3.08 2.87zm11.4 7.9c2 0 3.9-.6 5.2-1.77l-1.42-2.2c-.8.8-2.3 1.2-3.34 1.2-2.2 0-3.4-1.4-3.6-3h9.2v-.7c0-4.2-2.6-7.1-6.3-7.1-3.8 0-6.4 3-6.4 6.7 0 4.05 2.82 6.7 6.62 6.7zm2.9-7.9h-6.1c.17-1.27 1.05-2.83 3.1-2.83 2.2 0 3 1.6 3.1 2.87zm17.3 7.58v-9c0-2.5-1.3-4-4.03-4-2.08 0-3.6 1-4.4 2v-1.64h-3.3v12.76h3.3v-8.6c.53-.74 1.53-1.5 2.82-1.5 1.4 0 2.3.63 2.3 2.4v7.7h3.2z"/> </g> </svg> <h1>Uh Oh! Sqreen has detected an attack.</h1> <p>If you are the application owner, check the Sqreen <a href="https://my.sqreen.io/">dashboard</a> for more information.</p></div></body></html>
2
+
@@ -2,195 +2,285 @@
2
2
  # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
3
 
4
4
  require 'strscan'
5
+ require 'sqreen/exception'
6
+ require 'set'
5
7
 
6
- # the value located at the given binding
7
- class BindingAccessor
8
- PathElem = Struct.new(:kind, :value)
9
- attr_reader :path, :expression
10
-
11
- # Expression to be accessed
12
- # @param expression [String] expression to read
13
- # @param convert [Boolean] wheter to convert objects to simpler types (Array, Hash, String...)
14
- def initialize(expression, convert = false)
15
- @expression = expression
16
- @path = []
17
- @convert = convert
18
- parse(expression)
19
- end
8
+ module Sqreen
9
+ # the value located at the given binding
10
+ class BindingAccessor
11
+ PathElem = Struct.new(:kind, :value)
12
+ attr_reader :path, :expression, :final_transform
20
13
 
21
- # Resolve this expression for the give binding
22
- def resolve(binding, framework = nil, instance = nil, arguments = nil, cbdata = nil, last_return = nil)
23
- env = [framework, instance, arguments, cbdata, last_return]
24
- value = nil
25
- @path.each do |component|
26
- value = resolve_component(value, component, binding, env)
14
+ # Expression to be accessed
15
+ # @param expression [String] expression to read
16
+ # @param convert [Boolean] wheter to convert objects to
17
+ # simpler types (Array, Hash, String...)
18
+ def initialize(expression, convert = false)
19
+ @final_transform = nil
20
+ @expression = expression
21
+ @path = []
22
+ @convert = convert
23
+ parse(expression)
24
+ end
25
+
26
+ # Access data from the expression
27
+ def access(binding, framework = nil, instance = nil, arguments = nil, cbdata = nil, last_return = nil)
28
+ env = [framework, instance, arguments, cbdata, last_return]
29
+ value = nil
30
+ @path.each do |component|
31
+ value = resolve_component(value, component, binding, env)
32
+ end
33
+ value
34
+ end
35
+
36
+ # access and transform expression for the given binding
37
+ def resolve(*args)
38
+ value = access(*args)
39
+ value = transform(value) if @final_transform
40
+ return convert(value) if @convert
41
+ value
27
42
  end
28
- return convert(value) if @convert
29
- value
30
- end
31
43
 
32
- protected
44
+ protected
33
45
 
34
- STRING_KIND = 'string'.freeze
35
- SYMBOL_KIND = 'symbol'.freeze
36
- INTEGER_KIND = 'integer'.freeze
37
- LOCAL_VAR_KIND = 'local-variable'.freeze
38
- INSTANCE_VAR_KIND = 'instance-variable'.freeze
39
- CLASS_VAR_KIND = 'class-variable'.freeze
40
- GLOBAL_VAR_KIND = 'global-variable'.freeze
41
- CONSTANT_KIND = 'constant'.freeze
42
- METHOD_KIND = 'method'.freeze
43
- INDEX_KIND = 'index'.freeze
44
- SQREEN_VAR_KIND = 'sqreen-variable'.freeze
46
+ STRING_KIND = 'string'.freeze
47
+ SYMBOL_KIND = 'symbol'.freeze
48
+ INTEGER_KIND = 'integer'.freeze
49
+ LOCAL_VAR_KIND = 'local-variable'.freeze
50
+ INSTANCE_VAR_KIND = 'instance-variable'.freeze
51
+ CLASS_VAR_KIND = 'class-variable'.freeze
52
+ GLOBAL_VAR_KIND = 'global-variable'.freeze
53
+ CONSTANT_KIND = 'constant'.freeze
54
+ METHOD_KIND = 'method'.freeze
55
+ INDEX_KIND = 'index'.freeze
56
+ SQREEN_VAR_KIND = 'sqreen-variable'.freeze
45
57
 
46
- if binding.respond_to?(:local_variable_get)
47
- def get_local(name, bind)
48
- bind.local_variable_get(name)
58
+ if binding.respond_to?(:local_variable_get)
59
+ def get_local(name, bind)
60
+ bind.local_variable_get(name)
61
+ end
62
+ else
63
+ def get_local(name, bind)
64
+ eval(name, bind)
65
+ end
49
66
  end
50
- else
51
- def get_local(name, bind)
52
- eval(name, bind)
67
+
68
+ def resolve_component(current_value, component, binding, env)
69
+ case component[:kind]
70
+ when STRING_KIND, SYMBOL_KIND, INTEGER_KIND
71
+ component[:value]
72
+ when LOCAL_VAR_KIND
73
+ get_local(component[:value], binding)
74
+ when INSTANCE_VAR_KIND
75
+ current_value.instance_variable_get("@#{component[:value]}")
76
+ when CLASS_VAR_KIND
77
+ current_value.class.class_variable_get("@@#{component[:value]}")
78
+ when GLOBAL_VAR_KIND
79
+ instance_eval("$#{component[:value]}")
80
+ when CONSTANT_KIND
81
+ if current_value
82
+ current_value.const_get(component[:value].to_s)
83
+ else
84
+ Object.const_get(component[:value].to_s)
85
+ end
86
+ when METHOD_KIND
87
+ current_value.send(component[:value])
88
+ when INDEX_KIND
89
+ current_value[component[:value]]
90
+ when SQREEN_VAR_KIND
91
+ resolve_sqreen_variable(component[:value], *env)
92
+ else
93
+ raise "Do not know how to handle this component #{component.inspect}"
94
+ end
53
95
  end
54
- end
55
96
 
56
- def resolve_component(current_value, component, binding, env)
57
- case component[:kind]
58
- when STRING_KIND, SYMBOL_KIND, INTEGER_KIND
59
- component[:value]
60
- when LOCAL_VAR_KIND
61
- get_local(component[:value], binding)
62
- when INSTANCE_VAR_KIND
63
- current_value.instance_variable_get("@#{component[:value]}")
64
- when CLASS_VAR_KIND
65
- current_value.class.class_variable_get("@@#{component[:value]}")
66
- when GLOBAL_VAR_KIND
67
- instance_eval("$#{component[:value]}")
68
- when CONSTANT_KIND
69
- if current_value
70
- current_value.const_get(component[:value].to_s)
97
+ def resolve_sqreen_variable(what, framework, instance, args, cbdata, rv)
98
+ case what
99
+ when 'data'
100
+ cbdata
101
+ when 'rv'
102
+ rv
103
+ when 'args'
104
+ args
105
+ when 'inst'
106
+ instance
71
107
  else
72
- Object.const_get(component[:value].to_s)
108
+ framework.send(what)
73
109
  end
74
- when METHOD_KIND
75
- current_value.send(component[:value])
76
- when INDEX_KIND
77
- current_value[component[:value]]
78
- when SQREEN_VAR_KIND
79
- resolve_sqreen_variable(component[:value], *env)
80
- else
81
- raise "Do not know how to handle this component #{component.inspect}"
82
110
  end
83
- end
84
111
 
85
- def resolve_sqreen_variable(what, framework, instance, args, cbdata, rv)
86
- case what
87
- when 'data'
88
- cbdata
89
- when 'rv'
90
- rv
91
- when 'args'
92
- args
93
- when 'inst'
94
- instance
95
- else
96
- framework.send(what)
112
+ def parse(expression)
113
+ expression = extract_transform(expression)
114
+ @scan = StringScanner.new(expression)
115
+ until @scan.eos?
116
+ pos = @scan.pos
117
+ scalar = scan_scalar
118
+ if scalar
119
+ @path.push scalar
120
+ return
121
+ end
122
+ if @path.empty?
123
+ scan_push_variable
124
+ else
125
+ scan_push_method
126
+ end
127
+ scan_push_indexes
128
+ scan_push_more_constant if @scan.scan(/\./).nil?
129
+ raise Sqreen::Exception, error_state('Scan stuck') if @scan.pos == pos
130
+ end
131
+ ensure
132
+ @scan = nil
133
+ end
134
+
135
+ def extract_transform(expression)
136
+ parts = expression.split('|')
137
+ self.final_transform = parts.pop if parts.size > 1
138
+ parts.join('|').rstrip
97
139
  end
98
- end
99
140
 
100
- def parse(expression)
101
- @scan = StringScanner.new(expression)
102
- until @scan.eos?
103
- pos = @scan.pos
104
- scalar = scan_scalar
105
- if scalar
106
- @path.push scalar
107
- return
141
+ def final_transform=(transform)
142
+ transform.strip!
143
+ unless KNOWN_TRANSFORMS.include?(transform)
144
+ raise Sqreen::Exception, "Invalid transform #{transform}"
108
145
  end
109
- if @path.empty?
110
- scan_push_variable
111
- else
112
- scan_push_method
146
+ @final_transform = transform
147
+ end
148
+
149
+ def scan_scalar
150
+ if @scan.scan(/\d+/)
151
+ PathElem.new(INTEGER_KIND, @scan[0].to_i)
152
+ elsif @scan.scan(/:(\w+)/)
153
+ PathElem.new(SYMBOL_KIND, @scan[1].to_sym)
154
+ elsif @scan.scan(/'((?:\\.|[^\\'])*)'/)
155
+ PathElem.new(STRING_KIND, @scan[1])
113
156
  end
114
- scan_push_indexes
115
- scan_push_more_constant if @scan.scan(/\./).nil?
116
- raise error_state('Scan stuck') if @scan.pos == pos
117
157
  end
118
- ensure
119
- @scan = nil
120
- end
121
158
 
122
- def scan_scalar
123
- if @scan.scan(/\d+/)
124
- return PathElem.new(INTEGER_KIND, @scan[0].to_i)
125
- elsif @scan.scan(/:(\w+)/)
126
- return PathElem.new(SYMBOL_KIND, @scan[1].to_sym)
127
- elsif @scan.scan(/'((?:\\.|[^\\'])*)'/)
128
- return PathElem.new(STRING_KIND, @scan[1])
159
+ RUBY_IDENTIFIER_CHAR = if ''.respond_to? :encoding
160
+ '[\w\u0080-\u{10ffff}]'
161
+ else
162
+ '[\w\x80-\xFF]'
163
+ end
164
+
165
+ def scan_push_constant
166
+ return unless @scan.scan(/([A-Z]#{RUBY_IDENTIFIER_CHAR}+)/)
167
+ @path << PathElem.new(CONSTANT_KIND, @scan[1])
129
168
  end
130
- end
131
169
 
132
- RUBY_IDENTIFIER_CHAR = if ''.respond_to? :encoding
133
- '[\w\u0080-\u{10ffff}]'
134
- else
135
- '[\w\x80-\xFF]'
136
- end
170
+ def scan_push_more_constant
171
+ while @scan.scan(/::/)
172
+ unless scan_push_constant
173
+ raise Sqreen::Exception, error_state('No more constant')
174
+ end
175
+ end
176
+ end
137
177
 
138
- def scan_push_constant
139
- return unless @scan.scan(/([A-Z]#{RUBY_IDENTIFIER_CHAR}+)/)
140
- @path << PathElem.new(CONSTANT_KIND, @scan[1])
141
- end
178
+ def scan_push_variable
179
+ if @scan.scan(/\$(#{RUBY_IDENTIFIER_CHAR}+)/)
180
+ @path << PathElem.new(GLOBAL_VAR_KIND, @scan[1])
181
+ elsif @scan.scan(/@@(#{RUBY_IDENTIFIER_CHAR}+)/)
182
+ @path << PathElem.new(CLASS_VAR_KIND, @scan[1])
183
+ elsif @scan.scan(/@(#{RUBY_IDENTIFIER_CHAR}+)/)
184
+ @path << PathElem.new(INSTANCE_VAR_KIND, @scan[1])
185
+ elsif @scan.scan(/#\.(\w+)/)
186
+ @path << PathElem.new(SQREEN_VAR_KIND, @scan[1])
187
+ elsif scan_push_constant
188
+ nil
189
+ elsif @scan.scan(/(#{RUBY_IDENTIFIER_CHAR}+)/u)
190
+ @path << PathElem.new(LOCAL_VAR_KIND, @scan[1])
191
+ end
192
+ end
142
193
 
143
- def scan_push_more_constant
144
- while @scan.scan(/::/)
145
- raise error_state('No more constant') unless scan_push_constant
194
+ def scan_push_method
195
+ if @scan.scan(/@@(#{RUBY_IDENTIFIER_CHAR}+)/)
196
+ @path << PathElem.new(CLASS_VAR_KIND, @scan[1])
197
+ elsif @scan.scan(/@(#{RUBY_IDENTIFIER_CHAR}+)/)
198
+ @path << PathElem.new(INSTANCE_VAR_KIND, @scan[1])
199
+ elsif @scan.scan(/(#{RUBY_IDENTIFIER_CHAR}+)/)
200
+ @path << PathElem.new(METHOD_KIND, @scan[1])
201
+ end
146
202
  end
147
- end
148
203
 
149
- def scan_push_variable
150
- if @scan.scan(/\$(#{RUBY_IDENTIFIER_CHAR}+)/)
151
- return @path << PathElem.new(GLOBAL_VAR_KIND, @scan[1])
152
- elsif @scan.scan(/@@(#{RUBY_IDENTIFIER_CHAR}+)/)
153
- return @path << PathElem.new(CLASS_VAR_KIND, @scan[1])
154
- elsif @scan.scan(/@(#{RUBY_IDENTIFIER_CHAR}+)/)
155
- return @path << PathElem.new(INSTANCE_VAR_KIND, @scan[1])
156
- elsif @scan.scan(/#\.(\w+)/)
157
- return @path << PathElem.new(SQREEN_VAR_KIND, @scan[1])
158
- elsif scan_push_constant
159
- return
160
- elsif @scan.scan(/(#{RUBY_IDENTIFIER_CHAR}+)/u)
161
- return @path << PathElem.new(LOCAL_VAR_KIND, @scan[1])
204
+ def scan_push_indexes
205
+ while @scan.scan(/\[/)
206
+ scalar = scan_scalar
207
+ raise Sqreen::Exception, error_state('Invalid index') unless scalar
208
+ unless @scan.scan(/\]/)
209
+ raise Sqreen::Exception, error_state('Unfinished index')
210
+ end
211
+ @path << PathElem.new(INDEX_KIND, scalar[:value])
212
+ end
162
213
  end
163
- end
164
214
 
165
- def scan_push_method
166
- if @scan.scan(/@@(#{RUBY_IDENTIFIER_CHAR}+)/)
167
- return @path << PathElem.new(CLASS_VAR_KIND, @scan[1])
168
- elsif @scan.scan(/@(#{RUBY_IDENTIFIER_CHAR}+)/)
169
- return @path << PathElem.new(INSTANCE_VAR_KIND, @scan[1])
170
- elsif @scan.scan(/(#{RUBY_IDENTIFIER_CHAR}+)/)
171
- return @path << PathElem.new(METHOD_KIND, @scan[1])
215
+ def error_state(msg)
216
+ "#{msg} at #{@scan.pos} after #{@scan.string[0...@scan.pos]} (#{@scan.string})"
172
217
  end
173
- end
174
218
 
175
- def scan_push_indexes
176
- while @scan.scan(/\[/)
177
- scalar = scan_scalar
178
- raise error_state('Invalid index') unless scalar
179
- raise error_state('Unfinished index') unless @scan.scan(/\]/)
180
- @path << PathElem.new(INDEX_KIND, scalar[:value])
219
+ def convert(value)
220
+ case value
221
+ when ::Exception
222
+ { 'message' => value.message, 'backtrace' => value.backtrace }
223
+ else
224
+ value
225
+ end
181
226
  end
182
- end
183
227
 
184
- def error_state(msg)
185
- "#{msg} at #{@scan.pos} after #{@scan.string[0...@scan.pos]} (#{@scan.string})"
186
- end
228
+ # Available final transformations
229
+ module Transforms
230
+ def flat_keys(value, max_iter = 1000)
231
+ return nil if value.nil?
232
+ seen = Set.new
233
+ look_into = [value]
234
+ keys = []
235
+ idx = 0
236
+ until look_into.empty? || max_iter <= idx
237
+ idx += 1
238
+ val = look_into.pop
239
+ next unless seen.add?(val.object_id)
240
+ case val
241
+ when Hash
242
+ keys.concat(val.keys)
243
+ look_into.concat(val.values)
244
+ when Array
245
+ look_into.concat(val)
246
+ else
247
+ val.each { |v| look_into << v } if val.respond_to?(:each)
248
+ end
249
+ end
250
+ keys
251
+ end
187
252
 
188
- def convert(value)
189
- case value
190
- when Exception
191
- return { 'message' => value.message, 'backtrace' => value.backtrace }
192
- else
193
- return value
253
+ def flat_values(value, max_iter = 1000)
254
+ return nil if value.nil?
255
+ seen = Set.new
256
+ look_into = [value]
257
+ values = []
258
+ idx = 0
259
+ until look_into.empty? || max_iter <= idx
260
+ idx += 1
261
+ val = look_into.shift
262
+ next unless seen.add?(val.object_id)
263
+ case val
264
+ when Hash
265
+ look_into.concat(val.values)
266
+ when Array
267
+ look_into.concat(val)
268
+ else
269
+ if val.respond_to?(:each)
270
+ val.each { |v| look_into << v }
271
+ else
272
+ values << val
273
+ end
274
+ end
275
+ end
276
+ values
277
+ end
278
+ end
279
+ include Transforms
280
+ KNOWN_TRANSFORMS = Transforms.public_instance_methods.map(&:to_s)
281
+
282
+ def transform(value)
283
+ send(@final_transform, value) if @final_transform
194
284
  end
195
285
  end
196
286
  end