gda 1.0.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.
- checksums.yaml +7 -0
- data/.autotest +12 -0
- data/.gemtest +0 -0
- data/CHANGELOG.rdoc +6 -0
- data/Manifest.txt +27 -0
- data/README.rdoc +61 -0
- data/Rakefile +34 -0
- data/ext/gda/extconf.rb +19 -0
- data/ext/gda/gda.c +99 -0
- data/ext/gda/gda.h +18 -0
- data/ext/gda/gda_nodes.c +516 -0
- data/ext/gda/gda_nodes.h +9 -0
- data/ext/gda/gda_provider.c +61 -0
- data/ext/gda/gda_provider.h +7 -0
- data/ext/gda/gda_statement.c +58 -0
- data/ext/gda/gda_statement.h +6 -0
- data/lib/gda.rb +39 -0
- data/lib/gda/visitors/dot.rb +188 -0
- data/lib/gda/visitors/each.rb +18 -0
- data/lib/gda/visitors/max_depth.rb +29 -0
- data/lib/gda/visitors/visitor.rb +129 -0
- data/test/helper.rb +17 -0
- data/test/sqllog.sqlite3 +0 -0
- data/test/test_dot_visitor.rb +43 -0
- data/test/test_gda.rb +55 -0
- data/test/test_max_depth.rb +19 -0
- data/test/test_node_attributes.rb +159 -0
- data/test/test_nodes.rb +26 -0
- data/test/test_statement.rb +79 -0
- metadata +155 -0
data/test/helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'gda'
|
3
|
+
require 'sqlite3'
|
4
|
+
|
5
|
+
module GDA
|
6
|
+
class TestCase < MiniTest::Unit::TestCase
|
7
|
+
@@rails_sql = nil
|
8
|
+
|
9
|
+
def self.rails_sql
|
10
|
+
return @@rails_sql if @@rails_sql
|
11
|
+
|
12
|
+
db_file = File.join File.dirname(__FILE__), 'sqllog.sqlite3'
|
13
|
+
db = SQLite3::Database.new db_file
|
14
|
+
@@rails_sql = db.execute('SELECT * FROM sqllog').map(&:first)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/test/sqllog.sqlite3
ADDED
Binary file
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module GDA
|
4
|
+
class TestDotVisitor < TestCase
|
5
|
+
attr_reader :parser
|
6
|
+
|
7
|
+
class TestViz < Visitors::Dot
|
8
|
+
def initialize tc
|
9
|
+
super()
|
10
|
+
@tc = tc
|
11
|
+
end
|
12
|
+
|
13
|
+
Visitors::Visitor.private_instance_methods.grep(/^visit_(.*)/) do |method|
|
14
|
+
next if superclass.private_instance_methods(false).include?(method)
|
15
|
+
|
16
|
+
klass = $1.split('_').inject(Object) { |k,c| k.const_get c }
|
17
|
+
|
18
|
+
define_method(method) do |node|
|
19
|
+
flunk "#{klass} (#{method}) not tested yet"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def method_missing m, *args
|
24
|
+
return super unless @tc.respond_to?(m)
|
25
|
+
|
26
|
+
@tc.send m, *args
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def setup
|
31
|
+
super
|
32
|
+
@parser = GDA::SQL::Parser.new
|
33
|
+
@viz = TestViz.new(self)
|
34
|
+
end
|
35
|
+
|
36
|
+
rails_sql.uniq.each do |sql|
|
37
|
+
define_method(:"test_#{sql}") do
|
38
|
+
stmt = parser.parse sql
|
39
|
+
@viz.accept stmt.ast
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/test/test_gda.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module GDA
|
4
|
+
class TestParser < TestCase
|
5
|
+
attr_reader :parser
|
6
|
+
|
7
|
+
def setup
|
8
|
+
super
|
9
|
+
@parser = GDA::SQL::Parser.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_split
|
13
|
+
assert_equal ['test', '"table"'], GDA.sql_identifier_split("test.\"table\"")
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_parses
|
17
|
+
assert parser.parse('SELECT * FROM FOO')
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_providers
|
21
|
+
assert_kind_of Array, GDA::SQL.providers
|
22
|
+
assert_operator GDA::SQL.providers.length, :>, 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_get_provider
|
26
|
+
assert GDA::SQL::Provider.find SQL.providers.first
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_provider_name
|
30
|
+
name = SQL.providers.first
|
31
|
+
provider = SQL::Provider.find name
|
32
|
+
assert_equal name, provider.name
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_pg_parser
|
36
|
+
provider = SQL::Provider.find "PostgreSQL"
|
37
|
+
assert provider.parser.parse 'INSERT INTO "accounts" ("credit_limit", "firm_id", "firm_name") VALUES ($1, $2, $3) RETURNING "id"'
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_mysql_parser
|
41
|
+
provider = SQL::Provider.find "MySQL"
|
42
|
+
assert provider.parser.parse 'SELECT topics.* FROM topics WHERE topics.id = 147 LIMIT 1'
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_id_quote
|
47
|
+
provider = SQL::Provider.find "MySQL"
|
48
|
+
assert_equal '"1foo"', provider.quote("1foo")
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_error
|
52
|
+
assert_nil SQL::Provider.find "asdfasdfadsf"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module GDA
|
4
|
+
module Visitors
|
5
|
+
class TestMaxDepth < TestCase
|
6
|
+
attr_reader :parser
|
7
|
+
|
8
|
+
def setup
|
9
|
+
super
|
10
|
+
@parser = GDA::SQL::Parser.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_depth
|
14
|
+
stmt = parser.parse('SELECT * FROM FOO')
|
15
|
+
assert_equal 5, stmt.ast.max_depth
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module GDA
|
4
|
+
class TestNodeAttributes < TestCase
|
5
|
+
attr_reader :parser
|
6
|
+
|
7
|
+
class AttributeTest < Visitors::Visitor
|
8
|
+
def initialize tc
|
9
|
+
@tc = tc
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def visit_Array node
|
15
|
+
node.each { |n| accept n }
|
16
|
+
end
|
17
|
+
|
18
|
+
def visit_GDA_Nodes_Select node
|
19
|
+
assert_respond_to node, :distinct?
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
def visit_GDA_Nodes_Unknown node
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def visit_GDA_Nodes_Insert node
|
28
|
+
assert_string node, :on_conflict
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
def visit_GDA_Nodes_SelectField node
|
33
|
+
[:field_name, :table_name, :as].each do |m|
|
34
|
+
assert_string node, m
|
35
|
+
end
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
39
|
+
def visit_GDA_Nodes_Expr node
|
40
|
+
assert_string node, :value
|
41
|
+
assert_string node, :cast_as
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
def visit_GDA_Nodes_Function node
|
46
|
+
assert_string node, :function_name
|
47
|
+
super
|
48
|
+
end
|
49
|
+
|
50
|
+
def visit_GDA_Nodes_From node
|
51
|
+
super
|
52
|
+
end
|
53
|
+
|
54
|
+
def visit_GDA_Nodes_Table node
|
55
|
+
assert_string node, :table_name
|
56
|
+
super
|
57
|
+
end
|
58
|
+
|
59
|
+
def visit_GDA_Nodes_Update node
|
60
|
+
assert_string node, :on_conflict
|
61
|
+
super
|
62
|
+
end
|
63
|
+
|
64
|
+
def visit_GDA_Nodes_Operation node
|
65
|
+
assert_string node, :operator
|
66
|
+
super
|
67
|
+
end
|
68
|
+
|
69
|
+
def visit_GDA_Nodes_Delete node
|
70
|
+
super
|
71
|
+
end
|
72
|
+
|
73
|
+
def visit_GDA_Nodes_Order node
|
74
|
+
assert_boolean node, :asc
|
75
|
+
assert_string node, :collation_name
|
76
|
+
super
|
77
|
+
end
|
78
|
+
|
79
|
+
def visit_GDA_Nodes_RollbackSavepoint node
|
80
|
+
assert_string node, :__type__
|
81
|
+
assert_string node, :isolation_level
|
82
|
+
assert_string node, :trans_mode
|
83
|
+
assert_string node, :trans_name
|
84
|
+
super
|
85
|
+
end
|
86
|
+
|
87
|
+
alias :visit_GDA_Nodes_Begin :visit_GDA_Nodes_RollbackSavepoint
|
88
|
+
alias :visit_GDA_Nodes_Savepoint :visit_GDA_Nodes_RollbackSavepoint
|
89
|
+
alias :visit_GDA_Nodes_DeleteSavepoint :visit_GDA_Nodes_RollbackSavepoint
|
90
|
+
alias :visit_GDA_Nodes_Commit :visit_GDA_Nodes_RollbackSavepoint
|
91
|
+
alias :visit_GDA_Nodes_Rollback :visit_GDA_Nodes_RollbackSavepoint
|
92
|
+
|
93
|
+
def visit_GDA_Nodes_Field node
|
94
|
+
assert_string node, :field_name
|
95
|
+
super
|
96
|
+
end
|
97
|
+
|
98
|
+
def visit_GDA_Nodes_Join node
|
99
|
+
assert_string node, :join_type
|
100
|
+
assert_int node, :position
|
101
|
+
super
|
102
|
+
end
|
103
|
+
|
104
|
+
def visit_GDA_Nodes_Target node
|
105
|
+
assert_string node, :table_name
|
106
|
+
assert_string node, :as
|
107
|
+
super
|
108
|
+
end
|
109
|
+
|
110
|
+
def assert_boolean node, m
|
111
|
+
assert_respond_to node, m
|
112
|
+
if node.send(m)
|
113
|
+
assert_equal(true, node.send(m))
|
114
|
+
else
|
115
|
+
assert_equal(false, node.send(m))
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def assert_string node, m
|
120
|
+
assert_respond_to node, m
|
121
|
+
assert_kind_of(String, node.send(m)) if node.send(m)
|
122
|
+
end
|
123
|
+
|
124
|
+
def assert_int node, m
|
125
|
+
assert_respond_to node, m
|
126
|
+
assert_kind_of(Numeric, node.send(m)) if node.send(m)
|
127
|
+
end
|
128
|
+
|
129
|
+
Visitors::Visitor.private_instance_methods.grep(/^visit_(.*)/) do |method|
|
130
|
+
next if private_instance_methods(false).include?(method)
|
131
|
+
|
132
|
+
klass = $1.split('_').inject(Object) { |k,c| k.const_get c }
|
133
|
+
|
134
|
+
define_method(method) do |node|
|
135
|
+
flunk "#{klass} (#{method}) not tested yet"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def method_missing m, *args
|
140
|
+
return super unless @tc.respond_to?(m)
|
141
|
+
|
142
|
+
@tc.send m, *args
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def setup
|
147
|
+
super
|
148
|
+
@parser = GDA::SQL::Parser.new
|
149
|
+
@attr_tester = AttributeTest.new(self)
|
150
|
+
end
|
151
|
+
|
152
|
+
rails_sql.uniq.each do |sql|
|
153
|
+
define_method(:"test_#{sql}") do
|
154
|
+
stmt = parser.parse sql
|
155
|
+
@attr_tester.accept stmt.ast
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
data/test/test_nodes.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module GDA
|
4
|
+
class TestNodes < TestCase
|
5
|
+
attr_reader :parser
|
6
|
+
|
7
|
+
def setup
|
8
|
+
super
|
9
|
+
@parser = GDA::SQL::Parser.new
|
10
|
+
end
|
11
|
+
|
12
|
+
rails_sql.uniq.each do |sql|
|
13
|
+
define_method(:"test_#{sql}") do
|
14
|
+
stmt = parser.parse sql
|
15
|
+
stmt.ast.each do |node|
|
16
|
+
assert node
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_depth
|
22
|
+
stmt = parser.parse 'SELECT * FROM OMG WHERE 1 = 10'
|
23
|
+
assert_operator stmt.ast.to_a.length, :>, 1
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module GDA
|
4
|
+
module SQL
|
5
|
+
class TestStatement < TestCase
|
6
|
+
attr_reader :parser, :stmt
|
7
|
+
|
8
|
+
def setup
|
9
|
+
super
|
10
|
+
@parser = GDA::SQL::Parser.new
|
11
|
+
@stmt = parser.parse 'SELECT * FROM FOO WHERE 1 = 1 GROUP BY omg HAVING omg(id) < 2 ORDER BY foo, bar LIMIT 50 OFFSET 2'
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_serialize
|
15
|
+
assert stmt.serialize
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_from
|
19
|
+
assert stmt.ast
|
20
|
+
assert stmt.ast.from
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_distinct_expr
|
24
|
+
assert_nil stmt.ast.distinct_expr
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_expr_list
|
28
|
+
assert_equal 1, stmt.ast.expr_list.length
|
29
|
+
|
30
|
+
stmt.ast.expr_list.each do |node|
|
31
|
+
assert node
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_where_cond
|
36
|
+
assert stmt.ast.where_cond
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_group_by
|
40
|
+
assert stmt.ast.group_by
|
41
|
+
stmt.ast.group_by.each do |node|
|
42
|
+
assert node
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_having_cond
|
47
|
+
assert stmt.ast.having_cond
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_order_by
|
51
|
+
assert_equal 2, stmt.ast.order_by.length
|
52
|
+
stmt.ast.order_by.each do |node|
|
53
|
+
assert node
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_limit_count
|
58
|
+
assert stmt.ast.limit_count
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_limit_offset
|
62
|
+
assert stmt.ast.limit_offset
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_distinct?
|
66
|
+
refute stmt.ast.distinct?
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_each
|
70
|
+
yielded = false
|
71
|
+
stmt.ast.each do |node|
|
72
|
+
yielded = true
|
73
|
+
assert node
|
74
|
+
end
|
75
|
+
assert yielded
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
metadata
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gda
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aaron Patterson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-03-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rdoc
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.10'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.10'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake-compiler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.4.1
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.4.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sqlite3
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: hoe
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.5'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.5'
|
83
|
+
description: |-
|
84
|
+
An SQL parser. Wraps libgda in a loving embrace to give you a ruby level SQL
|
85
|
+
parser.
|
86
|
+
email:
|
87
|
+
- tenderlove@ruby-lang.org
|
88
|
+
executables: []
|
89
|
+
extensions:
|
90
|
+
- ext/gda/extconf.rb
|
91
|
+
extra_rdoc_files:
|
92
|
+
- CHANGELOG.rdoc
|
93
|
+
- Manifest.txt
|
94
|
+
- README.rdoc
|
95
|
+
files:
|
96
|
+
- .autotest
|
97
|
+
- CHANGELOG.rdoc
|
98
|
+
- Manifest.txt
|
99
|
+
- README.rdoc
|
100
|
+
- Rakefile
|
101
|
+
- ext/gda/extconf.rb
|
102
|
+
- ext/gda/gda.c
|
103
|
+
- ext/gda/gda.h
|
104
|
+
- ext/gda/gda_nodes.c
|
105
|
+
- ext/gda/gda_nodes.h
|
106
|
+
- ext/gda/gda_provider.c
|
107
|
+
- ext/gda/gda_provider.h
|
108
|
+
- ext/gda/gda_statement.c
|
109
|
+
- ext/gda/gda_statement.h
|
110
|
+
- lib/gda.rb
|
111
|
+
- lib/gda/visitors/dot.rb
|
112
|
+
- lib/gda/visitors/each.rb
|
113
|
+
- lib/gda/visitors/max_depth.rb
|
114
|
+
- lib/gda/visitors/visitor.rb
|
115
|
+
- test/helper.rb
|
116
|
+
- test/sqllog.sqlite3
|
117
|
+
- test/test_dot_visitor.rb
|
118
|
+
- test/test_gda.rb
|
119
|
+
- test/test_max_depth.rb
|
120
|
+
- test/test_node_attributes.rb
|
121
|
+
- test/test_nodes.rb
|
122
|
+
- test/test_statement.rb
|
123
|
+
- .gemtest
|
124
|
+
homepage: http://github.com/tenderlove/gda
|
125
|
+
licenses: []
|
126
|
+
metadata: {}
|
127
|
+
post_install_message:
|
128
|
+
rdoc_options:
|
129
|
+
- --main
|
130
|
+
- README.rdoc
|
131
|
+
require_paths:
|
132
|
+
- lib
|
133
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - '>='
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: 1.9.3
|
138
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
139
|
+
requirements:
|
140
|
+
- - '>='
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
requirements: []
|
144
|
+
rubyforge_project: gda
|
145
|
+
rubygems_version: 2.0.2
|
146
|
+
signing_key:
|
147
|
+
specification_version: 4
|
148
|
+
summary: An SQL parser
|
149
|
+
test_files:
|
150
|
+
- test/test_dot_visitor.rb
|
151
|
+
- test/test_gda.rb
|
152
|
+
- test/test_max_depth.rb
|
153
|
+
- test/test_node_attributes.rb
|
154
|
+
- test/test_nodes.rb
|
155
|
+
- test/test_statement.rb
|