marjoree 0.0.1 → 0.0.9

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 (174) hide show
  1. data/Marjoree.iml +14 -0
  2. data/README +9 -36
  3. data/bin/create_marj_structure.rb +75 -0
  4. data/bin/create_odbc_connections.rb +39 -0
  5. data/bin/odbc_connection_finder.rb +46 -0
  6. data/examples/contains_example.rb +1 -1
  7. data/examples/count_and_insert_example.rb +1 -1
  8. data/examples/select_example.rb +1 -1
  9. data/html/classes/ExpectedResultSet.html +60 -33
  10. data/html/classes/ExpectedResultSet.src/M000002.html +6 -5
  11. data/html/classes/ExpectedResultSet.src/M000003.html +5 -5
  12. data/html/classes/ExpectedResultSet.src/M000004.html +5 -5
  13. data/html/classes/ExpectedResultSet.src/M000005.html +18 -0
  14. data/html/classes/ExpectedResultSet.src/M000006.html +24 -0
  15. data/html/classes/ExpectedResultSet.src/M000007.html +23 -0
  16. data/html/classes/ExpectedResultSet.src/M000008.html +29 -0
  17. data/html/classes/Fixnum.html +287 -0
  18. data/html/classes/Fixnum.src/M000031.html +18 -0
  19. data/html/classes/Fixnum.src/M000034.html +18 -0
  20. data/html/classes/Fixnum.src/M000037.html +18 -0
  21. data/html/classes/Fixnum.src/M000039.html +18 -0
  22. data/html/classes/Fixnum.src/M000041.html +18 -0
  23. data/html/classes/Hash.html +156 -0
  24. data/html/classes/Hash.src/M000009.html +21 -0
  25. data/html/classes/Hash.src/M000010.html +20 -0
  26. data/html/classes/Marjoree.html +268 -151
  27. data/html/classes/Marjoree.src/M000057.html +19 -0
  28. data/html/classes/Marjoree.src/M000058.html +18 -0
  29. data/html/classes/{ExpectedResultSet.src/M000001.html → Marjoree.src/M000059.html} +4 -4
  30. data/html/classes/Marjoree.src/{M000024.html → M000060.html} +4 -4
  31. data/html/classes/Marjoree.src/{M000031.html → M000061.html} +4 -4
  32. data/html/classes/Marjoree.src/{M000026.html → M000062.html} +3 -3
  33. data/html/classes/Marjoree.src/{M000027.html → M000063.html} +3 -3
  34. data/html/classes/Marjoree.src/{M000028.html → M000064.html} +3 -3
  35. data/html/classes/Marjoree.src/{M000029.html → M000065.html} +5 -6
  36. data/html/classes/Marjoree.src/{M000030.html → M000066.html} +5 -5
  37. data/html/classes/Marjoree.src/M000067.html +19 -0
  38. data/html/classes/Marjoree.src/{M000032.html → M000068.html} +3 -3
  39. data/html/classes/{ResultSetWrapper.src/M000009.html → Marjoree.src/M000069.html} +4 -4
  40. data/html/classes/{ResultSetWrapper.src/M000010.html → Marjoree.src/M000070.html} +4 -4
  41. data/html/classes/{ResultSetWrapper.src/M000011.html → Marjoree.src/M000071.html} +4 -4
  42. data/html/classes/Marjoree.src/M000072.html +20 -0
  43. data/html/classes/Marjoree.src/M000073.html +20 -0
  44. data/html/classes/Marjoree.src/M000074.html +20 -0
  45. data/html/classes/Marjoree.src/{M000033.html → M000075.html} +3 -3
  46. data/html/classes/Marjoree.src/{M000034.html → M000076.html} +4 -4
  47. data/html/classes/Marjoree.src/{M000035.html → M000077.html} +2 -2
  48. data/html/classes/Marjoree.src/{M000036.html → M000078.html} +4 -3
  49. data/html/classes/Marjoree.src/{M000037.html → M000079.html} +1 -1
  50. data/html/classes/Marjoree.src/{M000038.html → M000080.html} +3 -3
  51. data/html/classes/Marjoree.src/{M000039.html → M000081.html} +3 -4
  52. data/html/classes/Marjoree.src/{M000040.html → M000082.html} +3 -3
  53. data/html/classes/Marjoree.src/{M000041.html → M000083.html} +3 -3
  54. data/html/classes/{ResultSetWrapper.src/M000008.html → Marjoree.src/M000084.html} +4 -4
  55. data/html/classes/ODBC.html +4 -0
  56. data/html/classes/ODBC/Error.html +12 -12
  57. data/html/classes/ODBC/Error.src/M000047.html +21 -0
  58. data/html/classes/ODBC/Error.src/{M000021.html → M000048.html} +2 -2
  59. data/html/classes/ODBC/TimeStamp.html +48 -18
  60. data/html/classes/ODBC/TimeStamp.src/{M000017.html → M000042.html} +2 -2
  61. data/html/classes/ODBC/TimeStamp.src/M000043.html +22 -0
  62. data/html/classes/ODBC/TimeStamp.src/{M000019.html → M000044.html} +2 -3
  63. data/html/classes/ODBC/TimeStamp.src/M000045.html +18 -0
  64. data/html/classes/ODBC/TimeStamp.src/M000046.html +18 -0
  65. data/html/classes/OdbcConnectionWrapper.html +244 -0
  66. data/html/classes/OdbcConnectionWrapper.src/M000023.html +18 -0
  67. data/html/classes/OdbcConnectionWrapper.src/M000024.html +18 -0
  68. data/html/classes/OdbcConnectionWrapper.src/M000025.html +22 -0
  69. data/html/classes/OdbcConnectionWrapper.src/M000026.html +25 -0
  70. data/html/classes/OdbcConnectionWrapper.src/M000027.html +20 -0
  71. data/html/classes/OdbcConnectionWrapper.src/M000028.html +28 -0
  72. data/html/classes/OdbcConnectionWrapper.src/M000029.html +24 -0
  73. data/html/classes/OdbcConnectionWrapper.src/M000030.html +30 -0
  74. data/html/classes/{ResultSetWrapper.html → ResultSet.html} +71 -94
  75. data/html/classes/ResultSet.src/M000011.html +27 -0
  76. data/html/classes/ResultSet.src/M000012.html +21 -0
  77. data/html/classes/ResultSet.src/M000013.html +23 -0
  78. data/html/classes/ResultSet.src/M000014.html +18 -0
  79. data/html/classes/ResultSet.src/M000015.html +18 -0
  80. data/html/classes/ResultSet.src/M000016.html +18 -0
  81. data/html/classes/ResultSet.src/M000017.html +18 -0
  82. data/html/classes/ResultSet.src/M000018.html +20 -0
  83. data/html/classes/ResultSet.src/M000019.html +18 -0
  84. data/html/classes/ResultSet.src/M000020.html +22 -0
  85. data/html/classes/ResultSet.src/M000021.html +23 -0
  86. data/html/classes/ResultSet.src/M000022.html +22 -0
  87. data/html/classes/Test.html +107 -0
  88. data/html/classes/Test/Unit.html +107 -0
  89. data/html/classes/Test/Unit/TestCase.html +257 -0
  90. data/html/classes/Test/Unit/TestCase.src/M000049.html +18 -0
  91. data/html/classes/Test/Unit/TestCase.src/M000050.html +18 -0
  92. data/html/classes/Test/Unit/TestCase.src/M000051.html +17 -0
  93. data/html/classes/Test/Unit/TestCase.src/M000052.html +17 -0
  94. data/html/classes/Test/Unit/TestCase.src/M000053.html +25 -0
  95. data/html/classes/Test/Unit/TestCase.src/M000054.html +18 -0
  96. data/html/classes/Test/Unit/TestCase.src/M000055.html +18 -0
  97. data/html/classes/Test/Unit/TestCase.src/M000056.html +35 -0
  98. data/html/created.rid +1 -1
  99. data/html/files/README.html +2 -51
  100. data/html/files/lib/expected_result_set_rb.html +1 -16
  101. data/html/files/lib/marjoree/core_rb.html +111 -0
  102. data/html/files/lib/marjoree/fixtures_rb.html +111 -0
  103. data/html/files/lib/marjoree/odbc_connection_wrapper_rb.html +109 -0
  104. data/html/files/lib/marjoree/odbc_rb.html +108 -0
  105. data/html/files/lib/{odbc_overrides_rb.html → marjoree/result_set_rb.html} +5 -5
  106. data/html/files/lib/{result_set_wrapper_rb.html → marjoree/time_rb.html} +5 -5
  107. data/html/files/lib/marjoree_rb.html +3 -4
  108. data/html/files/lib/run_marjoree_rb.html +145 -0
  109. data/html/files/lib/run_marjoree_rb.src/M000001.html +34 -0
  110. data/html/fr_class_index.html +7 -1
  111. data/html/fr_file_index.html +7 -2
  112. data/html/fr_method_index.html +84 -42
  113. data/lib/Marjoree.iml +12 -0
  114. data/lib/expected_result_set.rb +51 -24
  115. data/lib/marjoree.rb +2 -344
  116. data/lib/marjoree/core.rb +388 -0
  117. data/lib/marjoree/fixtures.rb +156 -0
  118. data/lib/marjoree/odbc.rb +45 -0
  119. data/lib/marjoree/odbc_connection_wrapper.rb +79 -0
  120. data/lib/marjoree/result_set.rb +165 -0
  121. data/lib/marjoree/sybase_definitions.rb +223 -0
  122. data/lib/marjoree/time.rb +31 -0
  123. data/lib/proc_param_info.txt +20 -0
  124. data/lib/run_marjoree.rb +31 -0
  125. data/pkg/marjoree-0.0.9.gem +0 -0
  126. data/rakefile.rb +3 -3
  127. data/tests/all_cruby_tests.rb +24 -0
  128. data/tests/all_jruby_tests.rb +22 -0
  129. data/tests/all_tests.rb +9 -6
  130. data/tests/fixtures/A.yml +3 -0
  131. data/tests/fixtures/B.yml +5 -0
  132. data/tests/fixtures/first_db/FIRST.yml +8 -0
  133. data/tests/fixtures/second_db/SECOND.yml +9 -0
  134. data/tests/marjoree/test_assert_results.rb +82 -0
  135. data/tests/marjoree/test_connection_details.rb +44 -0
  136. data/tests/{test_contains.rb → marjoree/test_contains.rb} +0 -0
  137. data/tests/{test_delete.rb → marjoree/test_delete.rb} +0 -0
  138. data/tests/marjoree/test_drop_user_objects.rb +52 -0
  139. data/tests/marjoree/test_expected_result_set.rb +111 -0
  140. data/tests/marjoree/test_fixtures.rb +112 -0
  141. data/tests/{test_insert.rb → marjoree/test_insert.rb} +0 -0
  142. data/tests/{test_marjoree.rb → marjoree/test_marjoree.rb} +14 -2
  143. data/tests/marjoree/test_multiple_db_fixtures.rb +35 -0
  144. data/tests/{test_num_rows.rb → marjoree/test_num_rows.rb} +0 -0
  145. data/tests/marjoree/test_odbc_connection_wrapper.rb +47 -0
  146. data/tests/{test_result_set_wrapper.rb → marjoree/test_result_set_wrapper.rb} +8 -8
  147. data/tests/marjoree/test_select.rb +55 -0
  148. data/tests/marjoree/test_single_odbc_connection_wrapper.rb +39 -0
  149. data/tests/{test_sproc.rb → marjoree/test_sproc.rb} +3 -4
  150. data/tests/marjoree/test_time.rb +25 -0
  151. data/tests/{test_time_stamp.rb → marjoree/test_time_stamp.rb} +10 -1
  152. data/tests/{test_truncate.rb → marjoree/test_truncate.rb} +0 -0
  153. data/tests/{test_update.rb → marjoree/test_update.rb} +14 -14
  154. data/tests/multiple_odbc_config/connections.yml +13 -0
  155. data/tests/single_odbc_config/connections.yml +3 -0
  156. metadata +214 -112
  157. data/html/classes/Marjoree.src/M000022.html +0 -19
  158. data/html/classes/Marjoree.src/M000023.html +0 -20
  159. data/html/classes/Marjoree.src/M000025.html +0 -18
  160. data/html/classes/Marjoree.src/M000042.html +0 -25
  161. data/html/classes/ODBC/Error.src/M000020.html +0 -21
  162. data/html/classes/ODBC/TimeStamp.src/M000018.html +0 -22
  163. data/html/classes/ResultSetWrapper.src/M000005.html +0 -27
  164. data/html/classes/ResultSetWrapper.src/M000006.html +0 -24
  165. data/html/classes/ResultSetWrapper.src/M000007.html +0 -23
  166. data/html/classes/ResultSetWrapper.src/M000012.html +0 -20
  167. data/html/classes/ResultSetWrapper.src/M000013.html +0 -18
  168. data/html/classes/ResultSetWrapper.src/M000014.html +0 -22
  169. data/html/classes/ResultSetWrapper.src/M000015.html +0 -23
  170. data/html/classes/ResultSetWrapper.src/M000016.html +0 -27
  171. data/lib/odbc_overrides.rb +0 -33
  172. data/lib/result_set_wrapper.rb +0 -193
  173. data/tests/test_expected_result_set.rb +0 -40
  174. data/tests/test_select.rb +0 -30
@@ -0,0 +1,156 @@
1
+ require 'test/unit'
2
+ require 'erb'
3
+ require 'yaml'
4
+ require 'marjoree'
5
+
6
+ class Test::Unit::TestCase
7
+ attr_reader :fixtures
8
+ @@fixture_path = 'fixtures'
9
+
10
+ def self.fixture_path=(path)
11
+ @@fixture_path = path
12
+ end
13
+
14
+ def self.fixture_path
15
+ @@fixture_path
16
+ end
17
+
18
+ def setup_with_fixtures
19
+ end
20
+
21
+ def teardown_with_fixtures
22
+ end
23
+
24
+ def self.fixtures(*tables)
25
+ self.module_eval <<-EOS
26
+
27
+ def find_fixture_file( fixture_name )
28
+ return Dir["#{Test::Unit::TestCase.fixture_path}/**/\#{fixture_name}.yml"].first
29
+ end
30
+
31
+ def connect_to_db_for_fixture( path )
32
+ path_elements = path.split( '/' )
33
+ odbc_name = path_elements[ path_elements.size - 2]
34
+
35
+ connect_me_to( odbc_name.eql?( 'fixtures' ) ? 'default' : odbc_name )
36
+ end
37
+
38
+ def connect_to_default
39
+ connect_me_to 'default'
40
+ end
41
+
42
+ def setup_with_fixtures
43
+ @fixtures = [#{tables.collect{ |table| ":#{table}"}.join(',')}]
44
+
45
+ empty_fixture_tables( @fixtures )
46
+
47
+ @fixtures.each do |fixture|
48
+ path = find_fixture_file( fixture )
49
+ yaml = IO.read(path)
50
+ rows = YAML.load(ERB.new(yaml).result(binding)).sort
51
+
52
+ connect_to_db_for_fixture( path )
53
+
54
+ rows.each do |name, map|
55
+ Marjoree.execute map.to_sql(fixture)
56
+ end
57
+ end
58
+
59
+ connect_to_default
60
+ end
61
+
62
+ def teardown_with_fixtures
63
+ empty_fixture_tables( fixtures )
64
+ end
65
+
66
+ def empty_fixture_tables( fixtures )
67
+ fixtures.reverse.each do |fixture|
68
+ path = find_fixture_file( fixture )
69
+ connect_to_db_for_fixture( path )
70
+
71
+ begin
72
+ Marjoree.execute "DELETE FROM \#{fixture}"
73
+ rescue=>e
74
+ puts "Failed to truncate \#{fixture}: \#{e}"
75
+ end
76
+
77
+ connect_to_default
78
+ end
79
+ end
80
+ EOS
81
+
82
+ tables.each do |table|
83
+ module_eval <<-EOS
84
+ def #{table}(key)
85
+ path = find_fixture_file( "#{table}" )
86
+ yaml = IO.read(path)
87
+ rows = YAML.load(ERB.new(yaml).result)
88
+ map = rows[key.to_s]
89
+
90
+ def map.id;
91
+ return fetch('id') if member?('id')
92
+ return fetch("id_#{table.to_s.downcase}")
93
+ end
94
+
95
+ def map.method_missing(name, *args)
96
+ return self[name.to_s] || defaults[name]
97
+ end
98
+
99
+ def map.with_defaults(defaults)
100
+ @defaults = defaults
101
+ self
102
+ end
103
+
104
+ def map.defaults
105
+ @defaults || {}
106
+ end
107
+ return map
108
+ end
109
+ EOS
110
+ unless table.to_s.downcase == table.to_s
111
+ module_eval <<-EOS
112
+ def #{table.to_s.downcase}(key)
113
+ #{table}(key)
114
+ end
115
+ EOS
116
+ end
117
+ end
118
+ end
119
+
120
+ def setup
121
+ setup_with_fixtures
122
+ end
123
+
124
+ def teardown
125
+ teardown_with_fixtures
126
+ end
127
+
128
+ def self.method_added(method)
129
+ case method.to_s
130
+ when 'setup'
131
+ unless method_defined?(:setup_without_fixtures)
132
+ alias_method :setup_without_fixtures, :setup
133
+ define_method(:setup) do
134
+ setup_with_fixtures
135
+ setup_without_fixtures
136
+ end
137
+ end
138
+ when 'teardown'
139
+ unless method_defined?(:teardown_without_fixtures)
140
+ alias_method :teardown_without_fixtures, :teardown
141
+ define_method(:teardown) do
142
+ teardown_without_fixtures
143
+ teardown_with_fixtures
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ class Hash
151
+ def to_sql(table)
152
+ columns = keys.join(',')
153
+ column_values = values.collect { |v| v.kind_of?(Numeric) ? v : "'#{v}'" }.join(',')
154
+ return "INSERT INTO #{table}(#{columns}) VALUES(#{column_values})"
155
+ end
156
+ end
@@ -0,0 +1,45 @@
1
+ require 'odbc'
2
+
3
+ module ODBC
4
+ class TimeStamp
5
+ alias_method :old_to_s, :to_s
6
+
7
+ def ==( pal )
8
+ return to_s.index( pal.to_s ) == 0
9
+ end
10
+
11
+ def to_s
12
+ datetime = old_to_s
13
+ date, time, fraction = datetime.split(" ")
14
+
15
+ fraction_text = (fraction == '0') ? '' : ".#{fraction}"
16
+ return "#{date} #{time}#{fraction_text}"
17
+ end
18
+
19
+ def self.from_date(date)
20
+ return ODBC::TimeStamp.new(date.strftime('%Y-%m-%d 0:0:0.000'))
21
+ end
22
+
23
+ def self.from_time(time)
24
+ return ODBC::TimeStamp.new(time.strftime('%Y-%m-%d %H:%M:%S.000'))
25
+ end
26
+
27
+ def inspect
28
+ "#{old_to_s.split[0]} #{old_to_s.split[1]}"
29
+ end
30
+
31
+ end
32
+
33
+ class Error
34
+ def error_code
35
+ start_index = to_s =~ /(\()/
36
+ end_index = to_s =~ /(\))/
37
+ end_index -= 1
38
+ return to_s.slice( (start_index + 1 ), (end_index - start_index ) ).to_i
39
+ end
40
+
41
+ def error_message
42
+ return to_s.split( /\]/ ).last.rstrip
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,79 @@
1
+ require 'erb'
2
+ require 'yaml'
3
+
4
+ class OdbcConnectionWrapper
5
+ @@odbc_config_path = "odbc_config/connections.yml"
6
+
7
+ def self.odbc_config_path=(path)
8
+ @@odbc_config_path = path
9
+ end
10
+
11
+ def self.odbc_config_path
12
+ @@odbc_config_path
13
+ end
14
+
15
+ def initialize
16
+ yaml = IO.read("#{OdbcConnectionWrapper.odbc_config_path}")
17
+ @odbc_config = YAML.load(ERB.new(yaml).result(binding))
18
+ @odbc_connections = {}
19
+ @default_odbc_name = @odbc_config.size == 1 ? @odbc_config.keys.first : @odbc_config['default']['odbc_connection']
20
+ connect_me_to( 'default' )
21
+ end
22
+
23
+ def connect_me_to( odbc_name )
24
+ odbc_name = @default_odbc_name if odbc_name == 'default'
25
+ @connection = @odbc_connections[odbc_name]
26
+ unless @connection
27
+ value = @odbc_config[odbc_name]
28
+ @connection = ODBC.connect(odbc_name, value['username'], value['password'] )
29
+ @odbc_connections[odbc_name]=@connection
30
+ end
31
+ $db = @connection
32
+ end
33
+
34
+ def disconnect_me
35
+ @odbc_connections.each do |odbc_name, connection|
36
+ connection.drop_all
37
+ end
38
+ end
39
+
40
+ def execute(sql, output_params = [])
41
+ begin
42
+ dbCall = @connection.prepare(sql)
43
+ begin
44
+ dbCall.execute
45
+ return ResultSet.new(dbCall, output_params)
46
+ rescue
47
+ raise ODBC::Error.new("Failed executing: #{sql}\nDue to: #{$!}")
48
+ end
49
+ ensure
50
+ dbCall.drop
51
+ end
52
+ end
53
+
54
+ def has_output_params?(proc_name)
55
+ begin
56
+ dbCall = @connection.procedure_columns proc_name
57
+ result_set = ResultSet.new(dbCall)
58
+ return result_set.contains?({ :COLUMN_TYPE => 4 })
59
+ ensure
60
+ dbCall.drop
61
+ end
62
+ end
63
+
64
+ def get_output_params(proc_name)
65
+ begin
66
+ dbCall = @connection.procedure_columns proc_name
67
+ result_set = ResultSet.new(dbCall)
68
+ result = []
69
+ result_set.collect do |hash|
70
+ if hash[:COLUMN_TYPE] == 4 #varchar
71
+ result << hash
72
+ end
73
+ end
74
+ return result
75
+ ensure
76
+ dbCall.drop
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,165 @@
1
+ class ResultSet
2
+ attr_reader :columns
3
+ attr_reader :hashes
4
+
5
+ def initialize(statement, output_param_names = [])
6
+ @padding = " "
7
+ @spacer = " "
8
+ @columns = statement.columns
9
+ @hashes = []
10
+
11
+ if output_param_names.length > 0
12
+ apply_output_params output_param_names, statement
13
+ else
14
+ extract_results statement
15
+ end
16
+ end
17
+
18
+ def apply_output_params(output_param_names, statement)
19
+ output_param_names.each do |output_param_name|
20
+ instance_variable_set(output_param_name, statement.fetch![0])
21
+ statement.more_results
22
+ end
23
+ end
24
+
25
+ def method_missing(name)
26
+ member_var = eval("@#{name}")
27
+ if !member_var.nil?
28
+ return member_var
29
+ else
30
+ return super
31
+ end
32
+ end
33
+
34
+ def is_output_param?(name)
35
+ return !eval("#{name}").nil?
36
+ end
37
+
38
+ def count
39
+ return @hashes.size
40
+ end
41
+
42
+ def size
43
+ return count
44
+ end
45
+
46
+ def empty?
47
+ return count == 0
48
+ end
49
+
50
+ def collect
51
+ @hashes.each do |hash|
52
+ yield hash
53
+ end
54
+ end
55
+
56
+ def has?(expected_result_set)
57
+ return contains?(expected_result_set.row_hashes)
58
+ end
59
+
60
+ def contains?(*expected_rows)
61
+ expected_rows.flatten.each do |expected|
62
+ return false unless contains_row?(expected)
63
+ end
64
+
65
+ return true
66
+ end
67
+
68
+ def contains_row?(expected)
69
+ expected_with_symbols = convert_keys_to_symbols(expected)
70
+ @hashes.each do |actual|
71
+ return true if actual == actual.merge(expected_with_symbols)
72
+ end
73
+
74
+ return false
75
+ end
76
+
77
+ def to_s
78
+ column_widths = widest_value_in_columns
79
+ result = create_header_row(column_widths)
80
+ result << "\n" + create_separator_row(column_widths)
81
+ @hashes.each { |row| result << "\n" + create_data_row(row, column_widths) }
82
+ return result
83
+ end
84
+
85
+ private
86
+
87
+ def create_separator_row(column_widths)
88
+ result = ""
89
+
90
+ column_widths.each do |width|
91
+ result << " "
92
+ num_bars = width + ( @padding.length * 2 )
93
+ num_bars.times { result << "-" }
94
+ end
95
+
96
+ result << " "
97
+
98
+ return result
99
+ end
100
+
101
+ def create_header_row( column_widths )
102
+ result = "|"
103
+
104
+ column_names.each_with_index do |header, i|
105
+ result << "#{@padding}" + create_entry(header, column_widths[i]) + "#{@padding}|"
106
+ end
107
+
108
+ return result
109
+ end
110
+
111
+ def create_data_row(row, column_widths)
112
+ result = "|"
113
+
114
+ column_names.each_with_index do |header, i|
115
+ result << "#{@padding}" + create_entry(row[header.to_sym].to_s, column_widths[i]) + "#{@padding}|"
116
+ end
117
+
118
+ return result
119
+ end
120
+
121
+ def create_entry( header, expected_width )
122
+ return header if header.length == expected_width
123
+
124
+ num_prefix_spaces = (expected_width - header.length)/2
125
+ num_postfix_spaces = expected_width - (num_prefix_spaces + header.length)
126
+ pre = ""
127
+ post = ""
128
+ num_prefix_spaces.times { pre << " " }
129
+ num_postfix_spaces.times { post << " " }
130
+
131
+ return pre + header + post
132
+ end
133
+
134
+ def widest_value_in_columns
135
+ result = []
136
+
137
+ column_names.each do |header|
138
+ largest = header.length
139
+ @hashes.each do |row|
140
+ if row[header.to_sym].to_s.length > largest
141
+ largest = row[header.to_sym].to_s.length
142
+ end
143
+ end
144
+
145
+ result << largest
146
+ puts
147
+ end
148
+
149
+ return result
150
+ end
151
+
152
+ def column_names
153
+ return columns.keys
154
+ end
155
+
156
+ def convert_keys_to_symbols(row)
157
+ result = {}
158
+ row.each { |key, value| result[key.to_sym] = value }
159
+ return result
160
+ end
161
+
162
+ def extract_results(statement)
163
+ statement.each_hash { |row| @hashes << convert_keys_to_symbols(row) }
164
+ end
165
+ end