ronin-sql 0.1.1 → 0.2.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.
Files changed (101) hide show
  1. data/History.txt +43 -0
  2. data/Manifest.txt +76 -23
  3. data/README.txt +31 -6
  4. data/Rakefile +2 -2
  5. data/lib/ronin/code/sql/{keyword.rb → add_column_clause.rb} +9 -13
  6. data/lib/ronin/code/sql/as.rb +47 -0
  7. data/lib/ronin/code/sql/asc.rb +38 -0
  8. data/lib/ronin/code/sql/between.rb +18 -12
  9. data/lib/ronin/code/sql/binary_expr.rb +12 -5
  10. data/lib/ronin/code/sql/clause.rb +37 -0
  11. data/lib/ronin/code/sql/code.rb +1 -1
  12. data/lib/ronin/code/sql/common_dialect.rb +16 -10
  13. data/lib/ronin/code/sql/create.rb +68 -0
  14. data/lib/ronin/code/sql/create_index.rb +9 -39
  15. data/lib/ronin/code/sql/create_table.rb +9 -56
  16. data/lib/ronin/code/sql/create_view.rb +7 -29
  17. data/lib/ronin/code/sql/default_values_clause.rb +38 -0
  18. data/lib/ronin/code/sql/delete.rb +10 -25
  19. data/lib/ronin/code/sql/desc.rb +38 -0
  20. data/lib/ronin/code/sql/dialect.rb +172 -52
  21. data/lib/ronin/code/sql/{builder.rb → drop.rb} +16 -20
  22. data/lib/ronin/code/sql/drop_index.rb +43 -0
  23. data/lib/ronin/code/sql/drop_table.rb +8 -16
  24. data/lib/ronin/code/sql/drop_view.rb +43 -0
  25. data/lib/ronin/code/sql/emittable.rb +102 -0
  26. data/lib/ronin/code/sql/exceptions/unknown_clause.rb +31 -0
  27. data/lib/ronin/code/sql/exceptions/unknown_dialect.rb +2 -2
  28. data/lib/ronin/code/sql/exceptions/unknown_statement.rb +31 -0
  29. data/lib/ronin/code/sql/exceptions.rb +3 -1
  30. data/lib/ronin/code/sql/expr.rb +7 -96
  31. data/lib/ronin/code/sql/field.rb +40 -23
  32. data/lib/ronin/code/sql/fields_clause.rb +48 -0
  33. data/lib/ronin/code/sql/from_clause.rb +44 -0
  34. data/lib/ronin/code/sql/function.rb +15 -12
  35. data/lib/ronin/code/sql/group_by_clause.rb +48 -0
  36. data/lib/ronin/code/sql/having_clause.rb +48 -0
  37. data/lib/ronin/code/sql/in.rb +9 -9
  38. data/lib/ronin/code/sql/injected_statement.rb +102 -0
  39. data/lib/ronin/code/sql/injection.rb +171 -5
  40. data/lib/ronin/code/sql/insert.rb +15 -45
  41. data/lib/ronin/code/sql/intersect_clause.rb +44 -0
  42. data/lib/ronin/code/sql/join_clause.rb +125 -0
  43. data/lib/ronin/code/sql/{like_expr.rb → like.rb} +19 -31
  44. data/lib/ronin/code/sql/limit_clause.rb +44 -0
  45. data/lib/ronin/code/sql/modifier.rb +50 -0
  46. data/lib/ronin/code/sql/offset_clause.rb +44 -0
  47. data/lib/ronin/code/sql/on_clause.rb +57 -0
  48. data/lib/ronin/code/sql/order_by_clause.rb +44 -0
  49. data/lib/ronin/code/sql/program.rb +170 -23
  50. data/lib/ronin/code/sql/rename_to_clause.rb +44 -0
  51. data/lib/ronin/code/sql/replace.rb +15 -17
  52. data/lib/ronin/code/sql/select.rb +46 -141
  53. data/lib/ronin/code/sql/set_clause.rb +44 -0
  54. data/lib/ronin/code/sql/statement.rb +117 -47
  55. data/lib/ronin/code/sql/token.rb +64 -0
  56. data/lib/ronin/code/sql/unary_expr.rb +9 -5
  57. data/lib/ronin/code/sql/union_all_clause.rb +44 -0
  58. data/lib/ronin/code/sql/union_clause.rb +44 -0
  59. data/lib/ronin/code/sql/update.rb +10 -31
  60. data/lib/ronin/code/sql/values_clause.rb +48 -0
  61. data/lib/ronin/code/sql/where_clause.rb +44 -0
  62. data/lib/ronin/code/sql.rb +1 -1
  63. data/lib/ronin/sql/error/error.rb +64 -0
  64. data/lib/ronin/sql/error/message.rb +64 -0
  65. data/lib/ronin/sql/error/pattern.rb +106 -0
  66. data/lib/ronin/sql/error/patterns.rb +100 -0
  67. data/lib/ronin/sql/error.rb +5 -30
  68. data/lib/ronin/sql/extensions/uri/http.rb +76 -21
  69. data/lib/ronin/sql/extensions/uri.rb +1 -1
  70. data/lib/ronin/sql/extensions.rb +2 -1
  71. data/lib/ronin/sql/injection.rb +213 -0
  72. data/lib/ronin/sql/version.rb +2 -2
  73. data/lib/ronin/sql.rb +7 -2
  74. data/spec/code/sql/create_examples.rb +19 -0
  75. data/spec/code/sql/create_index_spec.rb +25 -0
  76. data/spec/code/sql/create_table_spec.rb +27 -0
  77. data/spec/code/sql/create_view_spec.rb +16 -0
  78. data/spec/code/sql/delete_spec.rb +14 -0
  79. data/spec/code/sql/drop_examples.rb +10 -0
  80. data/spec/code/sql/drop_index_spec.rb +16 -0
  81. data/spec/code/sql/drop_table_spec.rb +16 -0
  82. data/spec/code/sql/drop_view_spec.rb +16 -0
  83. data/spec/code/sql/has_default_values_clause_examples.rb +10 -0
  84. data/spec/code/sql/has_fields_clause_examples.rb +15 -0
  85. data/spec/code/sql/has_from_clause_examples.rb +13 -0
  86. data/spec/code/sql/has_values_clause_examples.rb +15 -0
  87. data/spec/code/sql/has_where_clause_examples.rb +15 -0
  88. data/spec/code/sql/insert_spec.rb +21 -0
  89. data/spec/code/sql/replace_spec.rb +21 -0
  90. data/spec/code/sql/select_spec.rb +105 -0
  91. data/spec/code/sql/update_spec.rb +26 -0
  92. data/spec/helpers/code.rb +14 -0
  93. data/spec/sql/error_spec.rb +24 -0
  94. data/spec/sql/extensions/string_spec.rb +28 -0
  95. data/spec/sql_spec.rb +9 -0
  96. data/tasks/spec.rb +2 -0
  97. metadata +82 -29
  98. data/lib/ronin/code/sql/injection_builder.rb +0 -137
  99. data/lib/ronin/code/sql/injection_style.rb +0 -79
  100. data/lib/ronin/code/sql/style.rb +0 -170
  101. data/lib/ronin/sql/sql.rb +0 -83
@@ -3,7 +3,7 @@
3
3
  # Ronin SQL - A Ronin library providing support for SQL related security
4
4
  # tasks.
5
5
  #
6
- # Copyright (c) 2007-2008 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ # Copyright (c) 2007-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
7
7
  #
8
8
  # This program is free software; you can redistribute it and/or modify
9
9
  # it under the terms of the GNU General Public License as published by
@@ -21,56 +21,203 @@
21
21
  #++
22
22
  #
23
23
 
24
- require 'ronin/code/sql/style'
25
- require 'ronin/code/sql/builder'
24
+ require 'ronin/code/sql/dialect'
25
+ require 'ronin/code/sql/common_dialect'
26
+ require 'ronin/chars/char_set'
26
27
 
27
28
  module Ronin
28
29
  module Code
29
30
  module SQL
30
31
  class Program
31
32
 
33
+ # Name of the dialect
34
+ attr_reader :dialect
35
+
36
+ # Use single-line or multi-line style
37
+ attr_accessor :multiline
38
+
39
+ # Use lowercase style
40
+ attr_accessor :lowercase
41
+
42
+ # Compile with less parenthesis
43
+ attr_accessor :less_parenthesis
44
+
45
+ # Space string
46
+ attr_accessor :space
47
+
48
+ # New-line string
49
+ attr_accessor :newline
50
+
32
51
  def initialize(options={},&block)
33
- @builder = Builder.new(Style.new(options),&block)
52
+ options[:dialect] ||= :common
53
+ options[:symbols] ||= {}
54
+
55
+ if options.has_key?(:multiline)
56
+ @multiline = options[:multiline]
57
+ else
58
+ @multiline = true
59
+ end
60
+
61
+ if options.has_key?(:lowercase)
62
+ @lowercase = options[:lowercase]
63
+ else
64
+ @lowercase = false
65
+ end
66
+
67
+ if options.has_key?(:less_parens)
68
+ @less_parens = options[:less_parens]
69
+ else
70
+ @less_parens = false
71
+ end
72
+
73
+ @space = Chars::CharSet.new(options[:space] || ' ')
74
+ @newline = Chars::CharSet.new(options[:newline] || "\n")
75
+
76
+ @dialect = Dialect.get(options[:dialect]).new(options[:symbols])
77
+
78
+ instance_eval(&block) if block
34
79
  end
35
80
 
36
- def style
37
- @builder.style
81
+ def self.compile(options={},&block)
82
+ self.new(options,&block).compile
38
83
  end
39
84
 
40
- def dialect
41
- @builder.style.dialect.name
85
+ def symbols
86
+ @dialect.symbols
87
+ end
88
+
89
+ def select(*arguments,&block)
90
+ @dialect.statement(:select,*arguments,&block)
42
91
  end
43
92
 
44
93
  def compile
45
- @builder.compile
94
+ sql = []
95
+ stmt = ['']
96
+ prev = nil
97
+
98
+ each_string do |current|
99
+ if current == ';'
100
+ sql << stmt
101
+ stmt = ['']
102
+ elsif current == '('
103
+ next if @less_parens
104
+
105
+ stmt << current
106
+ elsif current == ')'
107
+ next if @less_parens
108
+
109
+ stmt.last << current
110
+ elsif (current == ',' || prev == '(')
111
+ stmt.last << current
112
+ elsif prev == ','
113
+ if @less_parens
114
+ stmt.last << current
115
+ else
116
+ stmt << current
117
+ end
118
+ else
119
+ stmt << current
120
+ end
121
+
122
+ prev = current
123
+ end
124
+
125
+ sql_string = ''
126
+
127
+ sql.each_with_index do |stmt,stmt_index|
128
+ stmt_string = ''
129
+
130
+ stmt.each_with_index do |token,token_index|
131
+ unless token.empty?
132
+ sql_string << token
133
+
134
+ unless token_index == (stmt.length - 1)
135
+ sql_string << space_token
136
+ end
137
+ end
138
+ end
139
+
140
+ sql_string << stmt_string
141
+
142
+ unless stmt_index == (sql.length - 1)
143
+ if @multiline
144
+ sql_string << newline_token
145
+ else
146
+ sql_string << ';'
147
+ sql_string << space_token
148
+ end
149
+ end
150
+ end
151
+
152
+ return sql_string
46
153
  end
47
154
 
48
- def to_s
49
- compile
155
+ alias to_s compile
156
+
157
+ protected
158
+
159
+ def space_token
160
+ @space.random_char
50
161
  end
51
162
 
52
- def self.compile(options={},&block)
53
- self.new(options,&block).compile
163
+ def newline_token
164
+ @newline.random_char
54
165
  end
55
166
 
56
- def uri_encode
57
- compile.uri_encode
167
+ def format_string(data)
168
+ "'" + data.to_s.sub("'","''") + "'"
58
169
  end
59
170
 
60
- def uri_escape
61
- compile.uri_escape
171
+ def format_token(token)
172
+ token = token.to_s
173
+
174
+ if @lowercase
175
+ token.downcase!
176
+ else
177
+ token.upcase!
178
+ end
179
+
180
+ return token
62
181
  end
63
182
 
64
- def html_encode
65
- compile.html_encode
183
+ def format(token)
184
+ if token.kind_of?(Token)
185
+ return format_token(token)
186
+ elsif token.kind_of?(String)
187
+ return format_string(token)
188
+ else
189
+ return token.to_s
190
+ end
66
191
  end
67
192
 
68
- def format_html(options={})
69
- compile.format_html(options)
193
+ def each_token(&block)
194
+ @dialect.each_token do |token|
195
+ block.call(token)
196
+ end
197
+
198
+ return self
70
199
  end
71
200
 
72
- def base64_encode
73
- compile.base64_encode
201
+ def each_string(&block)
202
+ each_token do |token|
203
+ block.call(format(token))
204
+ end
205
+
206
+ return self
207
+ end
208
+
209
+ def method_missing(name,*arguments,&block)
210
+ if @dialect.has_statement?(name)
211
+ return @dialect.enqueue_statement(name,*arguments,&block)
212
+ elsif @dialect.methods.include?(name.to_s)
213
+ return @dialect.send(name,*arguments,&block)
214
+ elsif (arguments.empty? && block.nil?)
215
+ if @dialect.symbols.has_symbol?(name)
216
+ return @dialect.symbols[name]
217
+ end
218
+ end
219
+
220
+ raise(NoMethodError,name.id2name)
74
221
  end
75
222
 
76
223
  end
@@ -0,0 +1,44 @@
1
+ #
2
+ #--
3
+ # Ronin SQL - A Ronin library providing support for SQL related security
4
+ # tasks.
5
+ #
6
+ # Copyright (c) 2007-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation; either version 2 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program; if not, write to the Free Software
20
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
+ #++
22
+ #
23
+
24
+ require 'ronin/code/sql/clause'
25
+
26
+ module Ronin
27
+ module Code
28
+ module SQL
29
+ class RenameToClause < Clause
30
+
31
+ attr_accessor :table
32
+
33
+ def initialize(table)
34
+ @table = table
35
+ end
36
+
37
+ def emit
38
+ emit_token('RENAME TO') + emit_value(@table)
39
+ end
40
+
41
+ end
42
+ end
43
+ end
44
+ end
@@ -3,7 +3,7 @@
3
3
  # Ronin SQL - A Ronin library providing support for SQL related security
4
4
  # tasks.
5
5
  #
6
- # Copyright (c) 2007-2008 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ # Copyright (c) 2007-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
7
7
  #
8
8
  # This program is free software; you can redistribute it and/or modify
9
9
  # it under the terms of the GNU General Public License as published by
@@ -22,34 +22,32 @@
22
22
  #
23
23
 
24
24
  require 'ronin/code/sql/statement'
25
+ require 'ronin/code/sql/fields_clause'
26
+ require 'ronin/code/sql/values_clause'
27
+ require 'ronin/code/sql/default_values_clause'
25
28
 
26
29
  module Ronin
27
30
  module Code
28
31
  module SQL
29
32
  class Replace < Statement
30
33
 
31
- def initialize(style,table=nil,values=nil,from=nil,&block)
32
- @table = table
33
- @values = values
34
- @from = from
34
+ clause :fields, FieldsClause
35
+ clause :default_values, DefaultValuesClause
36
+ clause :values, ValuesClause
35
37
 
36
- super(style,&block)
37
- end
38
+ def initialize(dialect,options={},&block)
39
+ @table = options[:table]
38
40
 
39
- def values(data)
40
- @values = data
41
+ super(dialect,options,&block)
41
42
  end
42
43
 
43
- def from(expr)
44
- @from = expr
44
+ def table(name)
45
+ @table = name
46
+ return value
45
47
  end
46
48
 
47
- def compile
48
- if @values.kind_of?(Hash)
49
- return compile_expr('REPLACE INTO',@table,compile_list(@values.keys),'VALUES',compile_datalist(@values.values))
50
- elsif @from.kind_of?(Select)
51
- return compile_expr('REPLACE INTO',@table,compile_list(@values),@from)
52
- end
49
+ def emit
50
+ emit_token('REPLACE INTO') + emit_value(@table) + super
53
51
  end
54
52
 
55
53
  end
@@ -3,7 +3,7 @@
3
3
  # Ronin SQL - A Ronin library providing support for SQL related security
4
4
  # tasks.
5
5
  #
6
- # Copyright (c) 2007-2008 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ # Copyright (c) 2007-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
7
7
  #
8
8
  # This program is free software; you can redistribute it and/or modify
9
9
  # it under the terms of the GNU General Public License as published by
@@ -22,163 +22,68 @@
22
22
  #
23
23
 
24
24
  require 'ronin/code/sql/statement'
25
+ require 'ronin/code/sql/fields_clause'
26
+ require 'ronin/code/sql/from_clause'
27
+ require 'ronin/code/sql/join_clause'
28
+ require 'ronin/code/sql/where_clause'
29
+ require 'ronin/code/sql/group_by_clause'
30
+ require 'ronin/code/sql/having_clause'
31
+ require 'ronin/code/sql/order_by_clause'
32
+ require 'ronin/code/sql/limit_clause'
33
+ require 'ronin/code/sql/offset_clause'
34
+ require 'ronin/code/sql/union_clause'
35
+ require 'ronin/code/sql/union_all_clause'
25
36
 
26
37
  module Ronin
27
38
  module Code
28
39
  module SQL
29
40
  class Select < Statement
30
41
 
31
- option_list :rows, [:all, :distinct]
32
-
33
- def initialize(style,tables=nil,options={:fields => nil, :where => nil},&block)
34
- @fields = options[:fields] || all
35
- @tables = tables
36
- @where = options[:where]
37
-
38
- super(style,&block)
39
- end
40
-
41
- def fields(*exprs)
42
- @fields = exprs
43
- return self
44
- end
45
-
46
- def tables(*expr)
47
- @tables = expr
48
- return self
49
- end
50
-
51
- def where(expr)
52
- @where = expr
53
- return self
54
- end
55
-
56
- def group_by(*fields)
57
- @group_by = fields
58
- return self
59
- end
60
-
61
- def having(expr)
62
- @having = expr
63
- return self
64
- end
65
-
66
- def order_by(*exprs)
67
- @order_by = exprs
68
- return self
69
- end
70
-
71
- def limit(value)
72
- @limit = value
73
- end
42
+ clause :fields, FieldsClause
43
+ clause :from, FromClause
44
+ clause :join, JoinClause
45
+ clause :where, WhereClause
46
+ clause :group_by, GroupByClause
47
+ clause :having, HavingClause
48
+ clause :order_by, OrderByClause
49
+ clause :limit, LimitClause
50
+ clause :offset, OffsetClause
51
+ clause :union, UnionClause
52
+ clause :union_all, UnionAllClause
53
+
54
+ def initialize(dialect,options={},&block)
55
+ @distinct_rows = options[:distinct_rows]
56
+ @all_rows = options[:all_rows]
57
+
58
+ super(dialect,options)
59
+
60
+ unless options[:fields]
61
+ fields(all)
62
+ end
74
63
 
75
- def offset(value)
76
- @limit = value
64
+ instance_eval(&block) if block
77
65
  end
78
66
 
79
- def union(table,opts={:fields => [], :where => nil},&block)
80
- @union = Select.new(@style,table,opts,&block)
67
+ def all_rows
68
+ @all_rows = true
81
69
  return self
82
70
  end
83
71
 
84
- def union_all(table,opts={:fields => [], :where => nil},&block)
85
- @union_all = Select.new(@style,table,opts,&block)
72
+ def distinct_rows
73
+ @distinct_rows = true
86
74
  return self
87
75
  end
88
76
 
89
- def join(table,on_expr)
90
- @join_type = :outer
91
- @join_table = table
92
- @join_on = on_expr
93
- end
94
-
95
- def inner_join(table,on_expr)
96
- @join_type = :inner
97
- @join_table = table
98
- @join_on = on_expr
99
- end
100
-
101
- def left_join(table,on_expr)
102
- @join_type = :left
103
- @join_table = table
104
- @join_on = on_expr
105
- end
106
-
107
- def right_join(table,on_expr)
108
- @join_type = :right
109
- @join_table = table
110
- @join_on = on_expr
111
- end
112
-
113
- def compile
114
- compile_expr(keyword_select,
115
- rows?,
116
- fields?,
117
- keyword_from,
118
- compile_list(@tables),
119
- where?,
120
- order_by?,
121
- having_by?,
122
- order_by?,
123
- limit?,
124
- unioned?)
125
- end
126
-
127
- protected
128
-
129
- keyword :select
130
- keyword :from
131
- keyword :where
132
- keyword :union
133
- keyword :union_all
134
- keyword :group_by, 'GROUP BY'
135
- keyword :having
136
- keyword :order_by, 'ORDER BY'
137
- keyword :limit
138
- keyword :offset
139
-
140
- def fields?
141
- if @fields.kind_of?(Array)
142
- unless @fields.empty?
143
- return compile_row(@fields)
144
- else
145
- return all.to_s
146
- end
147
- else
148
- return @fields.to_s
149
- end
150
- end
151
-
152
- def where?
153
- compile_expr(keyword_where,@where) if @where
154
- end
155
-
156
- def group_by?
157
- compile_expr(keyword_group_by,compile_row(@group_by)) if @group_by
158
- end
159
-
160
- def having_by?
161
- compile_expr(keyword_having,@having) if @having
162
- end
163
-
164
- def order_by?
165
- compile_expr(keyword_order_by,@order_by) if @order_by
166
- end
167
-
168
- def limit?
169
- compile_expr(keyword_limit,@limit,offset?) if @limit
170
- end
171
-
172
- def offset?
173
- compile_expr(keyword_offset,@offset) if @offset
174
- end
77
+ def emit
78
+ tokens = emit_token('SELECT')
175
79
 
176
- def unioned?
177
- if @union_all
178
- return compile_expr(keyword_union_all,@union_all)
179
- elsif @union
180
- return compile_expr(keyword_union,@union)
80
+ if @distinct_rows
81
+ tokens += emit_token('DISTINCT')
82
+ elsif @all_rows
83
+ tokens += emit_token('ALL')
181
84
  end
85
+
86
+ return tokens + super
182
87
  end
183
88
 
184
89
  end
@@ -0,0 +1,44 @@
1
+ #
2
+ #--
3
+ # Ronin SQL - A Ronin library providing support for SQL related security
4
+ # tasks.
5
+ #
6
+ # Copyright (c) 2007-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation; either version 2 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program; if not, write to the Free Software
20
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
+ #++
22
+ #
23
+
24
+ require 'ronin/code/sql/clause'
25
+
26
+ module Ronin
27
+ module Code
28
+ module SQL
29
+ class SetClause < Clause
30
+
31
+ attr_accessor :values
32
+
33
+ def initialize(*values)
34
+ @values = values
35
+ end
36
+
37
+ def emit
38
+ emit_token('WHERE') + emit_row(@values)
39
+ end
40
+
41
+ end
42
+ end
43
+ end
44
+ end