slacker 1.0.9 → 1.0.10

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 (40) hide show
  1. checksums.yaml +15 -0
  2. data/Gemfile +4 -4
  3. data/README.markdown +22 -22
  4. data/Rakefile +11 -11
  5. data/bin/slacker +28 -29
  6. data/bin/slacker_new +34 -34
  7. data/lib/slacker.rb +175 -175
  8. data/lib/slacker/application.rb +211 -206
  9. data/lib/slacker/command_line_formatter.rb +59 -59
  10. data/lib/slacker/command_line_formatter2.rb +61 -0
  11. data/lib/slacker/configuration.rb +59 -59
  12. data/lib/slacker/formatter.rb +14 -19
  13. data/lib/slacker/query_result_matcher.rb +178 -178
  14. data/lib/slacker/rspec_ext.rb +49 -49
  15. data/lib/slacker/rspec_monkey.rb +7 -7
  16. data/lib/slacker/sql.rb +39 -39
  17. data/lib/slacker/sql_preprocessor.rb +23 -23
  18. data/lib/slacker/string_helper.rb +16 -16
  19. data/lib/slacker/version.rb +3 -3
  20. data/lib/slacker_new/project/data/sample_1/my_table_expected_power_results.csv +11 -11
  21. data/lib/slacker_new/project/data/sample_1/my_table_initial_data.csv +11 -11
  22. data/lib/slacker_new/project/data/sample_1/numbers_expected_output.csv +3 -3
  23. data/lib/slacker_new/project/database.yml +9 -9
  24. data/lib/slacker_new/project/lib/helpers/my_helper.rb +1 -1
  25. data/lib/slacker_new/project/spec/sample_1.rb +66 -66
  26. data/lib/slacker_new/project/sql/sample_1/my_table_on_power.sql.erb +1 -1
  27. data/lib/slacker_new/project/sql/sample_1/play_with_numbers.sql.erb +16 -16
  28. data/lib/slacker_new/project/sql/sample_1/sysobjects_with_params.sql.erb +1 -1
  29. data/slacker.gemspec +27 -26
  30. data/spec/application_spec.rb +13 -13
  31. data/spec/query_result_matcher_spec.rb +268 -268
  32. data/spec/rspec_ext_spec.rb +87 -87
  33. data/spec/slacker_spec.rb +59 -59
  34. data/spec/spec_helper.rb +9 -9
  35. data/spec/test_files/matcher/test_1.csv +3 -3
  36. data/spec/test_files/test_slacker_project/data/test_1.csv +3 -3
  37. data/spec/test_files/test_slacker_project/sql/nest/nested_1.sql.erb +1 -1
  38. data/spec/test_files/test_slacker_project/sql/no_params.sql.erb +2 -2
  39. data/spec/test_files/test_slacker_project/sql/params.sql.erb +1 -1
  40. metadata +19 -20
@@ -1,49 +1,49 @@
1
- require 'slacker'
2
- require 'slacker/query_result_matcher'
3
- require 'csv'
4
-
5
- module Slacker
6
- module RSpecExt
7
- def query(query_string, options = {}, log_name = nil)
8
- log_name ||= Slacker.construct_log_name('query', query_string, options)
9
- sql = Slacker.sql_from_query_string(query_string, options)
10
- @results = Slacker.query_script(example, sql, log_name)
11
- if block_given?
12
- yield @results
13
- end
14
- @results
15
- end
16
-
17
- def sql
18
- Slacker.sql(self)
19
- end
20
-
21
- # Get a matcher which will compare the query results to a golden master
22
- def match(golden_master)
23
- QueryResultMatcher.new(Slacker.filter_golden_master(golden_master))
24
- end
25
-
26
- def csv(csv_file)
27
- Slacker.get_csv(csv_file)
28
- end
29
-
30
- def touch_csv(csv_file_or_object, fields, field_generators = {})
31
- Slacker.touch_csv(csv_file_or_object, fields, field_generators)
32
- end
33
-
34
- def load_csv(csv_file_or_object, table_name, log_name = nil)
35
- log_name ||= "load_csv '#{csv_file_or_object.kind_of?(CSV::Table) ? 'CSV Object' : csv_file_or_object }', 'table_name'"
36
- csv_object = case csv_file_or_object
37
- when String then Slacker.get_csv(csv_file_or_object)
38
- when CSV::Table then csv_file_or_object
39
- when Array then Slacker.hash_array_to_csv(csv_file_or_object)
40
- end
41
-
42
- Slacker.load_csv(example, csv_object, table_name, log_name)
43
- end
44
-
45
- def yes?(val)
46
- val != nil && val.downcase == 'yes'
47
- end
48
- end
49
- end
1
+ require 'slacker'
2
+ require 'slacker/query_result_matcher'
3
+ require 'csv'
4
+
5
+ module Slacker
6
+ module RSpecExt
7
+ def query(query_string, options = {}, log_name = nil)
8
+ log_name ||= Slacker.construct_log_name('query', query_string, options)
9
+ sql = Slacker.sql_from_query_string(query_string, options)
10
+ @results = Slacker.query_script(example, sql, log_name)
11
+ if block_given?
12
+ yield @results
13
+ end
14
+ @results
15
+ end
16
+
17
+ def sql
18
+ Slacker.sql(self)
19
+ end
20
+
21
+ # Get a matcher which will compare the query results to a golden master
22
+ def match(golden_master)
23
+ QueryResultMatcher.new(Slacker.filter_golden_master(golden_master))
24
+ end
25
+
26
+ def csv(csv_file)
27
+ Slacker.get_csv(csv_file)
28
+ end
29
+
30
+ def touch_csv(csv_file_or_object, fields, field_generators = {})
31
+ Slacker.touch_csv(csv_file_or_object, fields, field_generators)
32
+ end
33
+
34
+ def load_csv(csv_file_or_object, table_name, log_name = nil)
35
+ log_name ||= "load_csv '#{csv_file_or_object.kind_of?(CSV::Table) ? 'CSV Object' : csv_file_or_object }', 'table_name'"
36
+ csv_object = case csv_file_or_object
37
+ when String then Slacker.get_csv(csv_file_or_object)
38
+ when CSV::Table then csv_file_or_object
39
+ when Array then Slacker.hash_array_to_csv(csv_file_or_object)
40
+ end
41
+
42
+ Slacker.load_csv(example, csv_object, table_name, log_name)
43
+ end
44
+
45
+ def yes?(val)
46
+ val != nil && val.downcase == 'yes'
47
+ end
48
+ end
49
+ end
@@ -1,7 +1,7 @@
1
- # Monkeypatch a method to reset RSpec to reset it
2
- module RSpec
3
- def self.slacker_reset
4
- @world = nil
5
- @configuration = nil
6
- end
7
- end
1
+ # Monkeypatch a method to reset RSpec
2
+ module RSpec
3
+ def self.slacker_reset
4
+ @world = nil
5
+ @configuration = nil
6
+ end
7
+ end
@@ -1,39 +1,39 @@
1
- require 'slacker'
2
- require 'slacker/rspec_ext'
3
-
4
- module Slacker
5
- class Sql < BasicObject
6
- attr_accessor :base_folder, :rspec_ext
7
-
8
- def initialize(base_folder, rspec_ext)
9
- @base_folder = base_folder
10
- @rspec_ext = rspec_ext
11
- end
12
-
13
- def method_missing(method_name, *params, &block)
14
- ::Kernel.raise "Slacker::Sql.rspec_ext not initialized" if rspec_ext.nil?
15
- ::Kernel.raise "Missing folder #{base_folder}" if !::File.directory?(base_folder)
16
-
17
- method_name = method_name.to_s
18
-
19
- if ::File.directory?(::File.join(base_folder, method_name))
20
- ::Slacker::Sql.new(::File.join(base_folder, method_name), rspec_ext)
21
- else
22
- sql_file = ::Slacker.sql_file_from_method_name(base_folder, method_name)
23
- case sql_file
24
- when nil
25
- ::Kernel.raise "No SQL file found corresponding to method '#{method_name}' in folder #{base_folder}"
26
- else
27
- rspec_ext.query sql_file, *params, &block
28
- end
29
- end
30
- end
31
-
32
- def respond_to?(method_name)
33
- method_name = method_name.to_s
34
- ::Kernel.raise "Slacker::Sql.rspec_ext not initialized" if rspec_ext.nil?
35
- ::File.directory?(::File.join(base_folder, method_name)) ||
36
- !(::Slacker.sql_file_from_method_name(base_folder, method_name).nil?)
37
- end
38
- end
39
- end
1
+ require 'slacker'
2
+ require 'slacker/rspec_ext'
3
+
4
+ module Slacker
5
+ class Sql < BasicObject
6
+ attr_accessor :base_folder, :rspec_ext
7
+
8
+ def initialize(base_folder, rspec_ext)
9
+ @base_folder = base_folder
10
+ @rspec_ext = rspec_ext
11
+ end
12
+
13
+ def method_missing(method_name, *params, &block)
14
+ ::Kernel.raise "Slacker::Sql.rspec_ext not initialized" if rspec_ext.nil?
15
+ ::Kernel.raise "Missing folder #{base_folder}" if !::File.directory?(base_folder)
16
+
17
+ method_name = method_name.to_s
18
+
19
+ if ::File.directory?(::File.join(base_folder, method_name))
20
+ ::Slacker::Sql.new(::File.join(base_folder, method_name), rspec_ext)
21
+ else
22
+ sql_file = ::Slacker.sql_file_from_method_name(base_folder, method_name)
23
+ case sql_file
24
+ when nil
25
+ ::Kernel.raise "No SQL file found corresponding to method '#{method_name}' in folder #{base_folder}"
26
+ else
27
+ rspec_ext.query sql_file, *params, &block
28
+ end
29
+ end
30
+ end
31
+
32
+ def respond_to?(method_name)
33
+ method_name = method_name.to_s
34
+ ::Kernel.raise "Slacker::Sql.rspec_ext not initialized" if rspec_ext.nil?
35
+ ::File.directory?(::File.join(base_folder, method_name)) ||
36
+ !(::Slacker.sql_file_from_method_name(base_folder, method_name).nil?)
37
+ end
38
+ end
39
+ end
@@ -1,24 +1,24 @@
1
- module Slacker
2
- module SqlPreprocessor
3
- IVAR_REX = /%{\s*(.*?)\s*}/
4
-
5
- def self.executable_sql(sql, example)
6
- # Replace all appearances of %{} with the values of the corresponding example instance variables
7
- sql.gsub(IVAR_REX) do
8
- ivar = $1.to_sym
9
- instance = example.example_group_instance
10
-
11
- if instance.instance_variable_defined?(ivar)
12
- instance.instance_variable_get(ivar).to_s
13
- else
14
- raise "Example is missing instance variable #{ivar}"
15
- end
16
- end
17
- end
18
-
19
- def self.debuggable_sql(sql)
20
- # Replace all appearances of %{} with the names of the sql variables
21
- sql.gsub(IVAR_REX) {$1}
22
- end
23
- end
1
+ module Slacker
2
+ module SqlPreprocessor
3
+ IVAR_REX = /%{\s*(.*?)\s*}/
4
+
5
+ def self.executable_sql(sql, example)
6
+ # Replace all appearances of %{} with the values of the corresponding example instance variables
7
+ sql.gsub(IVAR_REX) do
8
+ ivar = $1.to_sym
9
+ instance = example.example_group_instance
10
+
11
+ if instance.instance_variable_defined?(ivar)
12
+ instance.instance_variable_get(ivar).to_s
13
+ else
14
+ raise "Example is missing instance variable #{ivar}"
15
+ end
16
+ end
17
+ end
18
+
19
+ def self.debuggable_sql(sql)
20
+ # Replace all appearances of %{} with the names of the sql variables
21
+ sql.gsub(IVAR_REX) {$1}
22
+ end
23
+ end
24
24
  end
@@ -1,17 +1,17 @@
1
- module Slacker
2
- module StringHelper
3
- class << self
4
- def camelize(lower_case_and_underscored_word)
5
- lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
6
- end
7
-
8
- def constantize(camel_cased_word)
9
- unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
10
- raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
11
- end
12
-
13
- Object.module_eval("::#{$1}", __FILE__, __LINE__)
14
- end
15
- end
16
- end
1
+ module Slacker
2
+ module StringHelper
3
+ class << self
4
+ def camelize(lower_case_and_underscored_word)
5
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
6
+ end
7
+
8
+ def constantize(camel_cased_word)
9
+ unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
10
+ raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
11
+ end
12
+
13
+ Object.module_eval("::#{$1}", __FILE__, __LINE__)
14
+ end
15
+ end
16
+ end
17
17
  end
@@ -1,3 +1,3 @@
1
- module Slacker
2
- VERSION = "1.0.9"
3
- end
1
+ module Slacker
2
+ VERSION = "1.0.10"
3
+ end
@@ -1,11 +1,11 @@
1
- "x","y","power"
2
- "2","1","2"
3
- "3","2","9"
4
- "4","3","64"
5
- "5","4","625"
6
- "4","2","16"
7
- "3","3","27"
8
- "2","4","16"
9
- "1","5","1"
10
- "-1","2","1"
11
- "-2","5","-32"
1
+ "x","y","power"
2
+ "2","1","2"
3
+ "3","2","9"
4
+ "4","3","64"
5
+ "5","4","625"
6
+ "4","2","16"
7
+ "3","3","27"
8
+ "2","4","16"
9
+ "1","5","1"
10
+ "-1","2","1"
11
+ "-2","5","-32"
@@ -1,11 +1,11 @@
1
- "x","y"
2
- 2,1
3
- 3,2
4
- 4,3
5
- 5,4
6
- 4,2
7
- 3,3
8
- 2,4
9
- 1,5
10
- -1,2
11
- -2,5
1
+ "x","y"
2
+ 2,1
3
+ 3,2
4
+ 4,3
5
+ 5,4
6
+ 4,2
7
+ 3,3
8
+ 2,4
9
+ 1,5
10
+ -1,2
11
+ -2,5
@@ -1,3 +1,3 @@
1
- "p","s"
2
- 2,34
3
- 12,44
1
+ "p","s"
2
+ 2,34
3
+ 12,44
@@ -1,9 +1,9 @@
1
- # Database connection.
2
- # When Slacker is executed, it will attempt to connect to this database.
3
-
4
- # Replace the following with your connection information.
5
- # Note that at this point Slacker only works with SQL Server authentication.
6
- server: my_server
7
- database: my_database
8
- user: user_name
9
- password: password
1
+ # Database connection.
2
+ # When Slacker is executed, it will attempt to connect to this database.
3
+
4
+ # Replace the following with your connection information.
5
+ # Note that at this point Slacker only works with SQL Server authentication.
6
+ server: my_server
7
+ database: my_database
8
+ user: user_name
9
+ password: password
@@ -1,2 +1,2 @@
1
- module MyHelper
1
+ module MyHelper
2
2
  end
@@ -1,66 +1,66 @@
1
- # Method "describe" opens up an example group.
2
- describe 'My database' do
3
- # Simple inline query example.
4
- it 'contains system tables' do
5
- # Make sure we have at least one system object in the database.
6
- query("select * from sysobjects where xtype = 'S';").count.should > 0
7
- end
8
-
9
- # The same query, this time using a SQL template stored in file "sql/sample_1/sysobject.sql.erb".
10
- it 'contains system tables (take two)' do
11
- # Every (*.sql.erb) file in folder "sql" can be called as a method on object "sql".
12
- # Subfolders of folder "sql" appear as children of object "sql" with their (*.sql.erb) files automatically available as methods.
13
- sql.sample_1.sysobjects.count.should > 0
14
- end
15
-
16
- # This time we'll use a parameterized template.
17
- it 'contains system tables (take three)' do
18
- # Every template can accept parameters; see file "sql/sample_1/sysobject_with_params.sql.erb".
19
- sql.sample_1.sysobjects_with_params(:xtype => 'S').count.should > 0
20
- end
21
-
22
- # SQL Templates can contain multiple statements and can return multiple resultsets.
23
- it 'can play with numbers' do
24
- # Note that this time we're calling the template with a block which receives the results as a block parameter.
25
- sql.sample_1.play_with_numbers(:x => 2, :y => 12) do |results|
26
- # The results object contains an array of all the resultsets generated by the query script.
27
- # A resultset contains an array of records. Each record is a hash of field => value pairs.
28
-
29
- # First resultset; First record; Column "product".
30
- results[0][0][:product].should == 24
31
-
32
- # A resultset can be matched directly against an array of hashes using method "match".
33
- results[1].should match([{:x => 2, :y => 12, :sum => 14}])
34
-
35
- # Or against a CSV file stored in project's "data" folder (see file "data/sample_1/numbers_expected_output.csv").
36
- results[2].should match('sample_1/numbers_expected_output.csv')
37
-
38
- # A resultset's values can be matched one-by-one.
39
- results[2][0][:p].should == 2
40
- results[2][0][:s].should == 34
41
- results[2][1][:p].should == 12
42
- results[2][1][:s].should == 44
43
- end
44
- end
45
-
46
- # Every "it" (example) is executed in a T-SQL transaction which is rolled back once the example is complete.
47
- # No example can ever interfere with the results of another example.
48
- #
49
- # CSV files can be used to load data directly into a table.
50
- # In this example, we will create a table, populate it with data,
51
- # calculate the exponentiation of one column based on another column
52
- # and verify the results against an expected resultset stored in a CSV file.
53
- it 'can play with numbers (take two)' do
54
- # Create the table - see file "sql/sample_1/create_my_table.sql.erb".
55
- sql.sample_1.create_my_table
56
- # We can populate any table with data from the "data" folder by calling method "load_csv".
57
- # See file "data/sample_1/my_table_initial_data.csv".
58
- load_csv('sample_1/my_table_initial_data.csv', 'MyTable')
59
-
60
- # Now let's test the system scalar function Power.
61
- # We will use it in a query expression executed agaings MyTable and we
62
- # will compare the results against a CSV file - we should expect them to match.
63
- # See files "sql/sample_1/my_table_on_power.sql.erb" and "data/sample_1/my_table_expected_power_results.csv".
64
- sql.sample_1.my_table_on_power.should match('sample_1/my_table_expected_power_results.csv')
65
- end
66
- end
1
+ # Method "describe" opens up an example group.
2
+ describe 'My database' do
3
+ # Simple inline query example.
4
+ it 'contains system tables' do
5
+ # Make sure we have at least one system object in the database.
6
+ query("select * from sysobjects where xtype = 'S';").count.should > 0
7
+ end
8
+
9
+ # The same query, this time using a SQL template stored in file "sql/sample_1/sysobject.sql.erb".
10
+ it 'contains system tables (take two)' do
11
+ # Every (*.sql.erb) file in folder "sql" can be called as a method on object "sql".
12
+ # Subfolders of folder "sql" appear as children of object "sql" with their (*.sql.erb) files automatically available as methods.
13
+ sql.sample_1.sysobjects.count.should > 0
14
+ end
15
+
16
+ # This time we'll use a parameterized template.
17
+ it 'contains system tables (take three)' do
18
+ # Every template can accept parameters; see file "sql/sample_1/sysobject_with_params.sql.erb".
19
+ sql.sample_1.sysobjects_with_params(:xtype => 'S').count.should > 0
20
+ end
21
+
22
+ # SQL Templates can contain multiple statements and can return multiple resultsets.
23
+ it 'can play with numbers' do
24
+ # Note that this time we're calling the template with a block which receives the results as a block parameter.
25
+ sql.sample_1.play_with_numbers(:x => 2, :y => 12) do |results|
26
+ # The results object contains an array of all the resultsets generated by the query script.
27
+ # A resultset contains an array of records. Each record is a hash of field => value pairs.
28
+
29
+ # First resultset; First record; Column "product".
30
+ results[0][0][:product].should == 24
31
+
32
+ # A resultset can be matched directly against an array of hashes using method "match".
33
+ results[1].should match([{:x => 2, :y => 12, :sum => 14}])
34
+
35
+ # Or against a CSV file stored in project's "data" folder (see file "data/sample_1/numbers_expected_output.csv").
36
+ results[2].should match('sample_1/numbers_expected_output.csv')
37
+
38
+ # A resultset's values can be matched one-by-one.
39
+ results[2][0][:p].should == 2
40
+ results[2][0][:s].should == 34
41
+ results[2][1][:p].should == 12
42
+ results[2][1][:s].should == 44
43
+ end
44
+ end
45
+
46
+ # Every "it" (example) is executed in a T-SQL transaction which is rolled back once the example is complete.
47
+ # No example can ever interfere with the results of another example.
48
+ #
49
+ # CSV files can be used to load data directly into a table.
50
+ # In this example, we will create a table, populate it with data,
51
+ # calculate the exponentiation of one column based on another column
52
+ # and verify the results against an expected resultset stored in a CSV file.
53
+ it 'can play with numbers (take two)' do
54
+ # Create the table - see file "sql/sample_1/create_my_table.sql.erb".
55
+ sql.sample_1.create_my_table
56
+ # We can populate any table with data from the "data" folder by calling method "load_csv".
57
+ # See file "data/sample_1/my_table_initial_data.csv".
58
+ load_csv('sample_1/my_table_initial_data.csv', 'MyTable')
59
+
60
+ # Now let's test the system scalar function Power.
61
+ # We will use it in a query expression executed agaings MyTable and we
62
+ # will compare the results against a CSV file - we should expect them to match.
63
+ # See files "sql/sample_1/my_table_on_power.sql.erb" and "data/sample_1/my_table_expected_power_results.csv".
64
+ sql.sample_1.my_table_on_power.should match('sample_1/my_table_expected_power_results.csv')
65
+ end
66
+ end