cql 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/lib/cql.rb +18 -11
  3. data/lib/cql/dsl.rb +14 -2
  4. data/lib/cql/filters.rb +12 -6
  5. data/lib/cql/map_reduce.rb +29 -11
  6. data/lib/cql/model_dsl.rb +18 -0
  7. data/lib/cql/queriable.rb +14 -0
  8. data/lib/cql/sso_filters.rb +3 -2
  9. data/lib/cql/version.rb +1 -1
  10. data/testing/cql_test_model.rb +42 -0
  11. data/testing/cucumber/features/clauses/as_clause.feature +136 -0
  12. data/testing/cucumber/features/clauses/from_clause.feature +126 -0
  13. data/testing/cucumber/features/clauses/select_clause.feature +117 -0
  14. data/testing/cucumber/features/clauses/transform_clause.feature +153 -0
  15. data/testing/cucumber/features/clauses/with_clause.feature +363 -0
  16. data/testing/cucumber/features/dsl.feature +77 -0
  17. data/testing/cucumber/features/model_querying.feature +18 -0
  18. data/testing/cucumber/features/repository.feature +23 -0
  19. data/testing/cucumber/step_definitions/query_steps.rb +7 -0
  20. data/testing/cucumber/step_definitions/setup_steps.rb +25 -0
  21. data/testing/cucumber/step_definitions/verification_steps.rb +78 -0
  22. data/testing/cucumber/support/env.rb +24 -0
  23. data/testing/cucumber/support/transforms.rb +3 -0
  24. data/testing/fixtures/features/combined/a/f1_4_scenarios_5_so.feature +59 -0
  25. data/testing/fixtures/features/combined/a/f2_7_scenarios_2_so.feature +43 -0
  26. data/testing/fixtures/features/combined/a/f3_2_scenarios_3_so.feature +30 -0
  27. data/testing/fixtures/features/combined/b/f1_1_tag.feature +6 -0
  28. data/testing/fixtures/features/combined/b/f2_2_tags.feature +6 -0
  29. data/testing/fixtures/features/combined/b/f3_3_tags.feature +6 -0
  30. data/testing/fixtures/features/examples/basic/test_with_scenarios.feature +15 -0
  31. data/testing/fixtures/features/examples/filters/tag_count/simple.feature +21 -0
  32. data/testing/fixtures/features/examples/filters/tag_count/simple2.feature +21 -0
  33. data/testing/fixtures/features/examples/filters/tags/simple.feature +34 -0
  34. data/testing/fixtures/features/examples/filters/tags2/simple.feature +34 -0
  35. data/testing/fixtures/features/examples/filters/tags2/simple2.feature +34 -0
  36. data/testing/fixtures/features/examples/multiple_examples/test_with_scenarios.feature +43 -0
  37. data/testing/fixtures/features/examples/name_filter/name.feature +19 -0
  38. data/testing/fixtures/features/got/Lannisters.feature +24 -0
  39. data/testing/fixtures/features/got/Starks.feature +18 -0
  40. data/testing/fixtures/features/scen_outlines/basic/test_with_scenarios.feature +15 -0
  41. data/testing/fixtures/features/scen_outlines/filters/tag_count/simple.feature +21 -0
  42. data/testing/fixtures/features/scen_outlines/filters/tag_count/simple2.feature +21 -0
  43. data/testing/fixtures/features/scen_outlines/filters/tags/simple.feature +34 -0
  44. data/testing/fixtures/features/scen_outlines/filters/tags2/simple.feature +34 -0
  45. data/testing/fixtures/features/scen_outlines/filters/tags2/simple2.feature +34 -0
  46. data/testing/fixtures/features/scen_outlines/line_count/simple.feature +12 -0
  47. data/testing/fixtures/features/scen_outlines/line_count/simple2.feature +16 -0
  48. data/testing/fixtures/features/scen_outlines/line_filter/ll.feature +13 -0
  49. data/testing/fixtures/features/scen_outlines/multiple_examples/test_with_scenarios.feature +43 -0
  50. data/testing/fixtures/features/scen_outlines/name_filter/name.feature +19 -0
  51. data/testing/fixtures/features/scenario/line_count/simple.feature +9 -0
  52. data/testing/fixtures/features/scenario/line_count/simple2.feature +12 -0
  53. data/testing/fixtures/features/scenario/line_filter/ll.feature +9 -0
  54. data/testing/fixtures/features/scenario/name_filter/name.feature +13 -0
  55. data/testing/fixtures/features/scenario/simple/simple.feature +8 -0
  56. data/testing/fixtures/features/scenario/simple/test.feature +9 -0
  57. data/testing/fixtures/features/scenario/simple/test2.feature +5 -0
  58. data/testing/fixtures/features/scenario/simple/test_full.feature +22 -0
  59. data/testing/fixtures/features/scenario/simple2/test_full.feature +23 -0
  60. data/testing/fixtures/features/scenario/table/simple.feature +11 -0
  61. data/testing/fixtures/features/scenario/tag_count/simple.feature +17 -0
  62. data/testing/fixtures/features/scenario/tag_count/simple2.feature +17 -0
  63. data/testing/fixtures/features/scenario/tagged_features/simple.feature +8 -0
  64. data/testing/fixtures/features/scenario/tagged_features/test.feature +10 -0
  65. data/testing/fixtures/features/scenario/tagged_features/test2.feature +6 -0
  66. data/testing/fixtures/features/scenario/tagged_features/test_full.feature +22 -0
  67. data/testing/fixtures/features/scenario/tags/simple.feature +24 -0
  68. data/testing/fixtures/features/scenario/tags2/simple.feature +24 -0
  69. data/testing/fixtures/features/scenario/tags2/simple2.feature +24 -0
  70. data/testing/fixtures/features/scenario/tags3/simple.feature +21 -0
  71. data/testing/gemfiles/cuke_modeler0.gemfile +30 -0
  72. data/testing/gemfiles/cuke_modeler1.gemfile +30 -0
  73. data/testing/rspec/spec/dsl_spec.rb +600 -0
  74. data/testing/rspec/spec/filter_example_spec.rb +65 -0
  75. data/testing/rspec/spec/filter_feature_dsl_spec.rb +286 -0
  76. data/testing/rspec/spec/filter_sso_spec.rb +202 -0
  77. data/testing/rspec/spec/line_count_filterable_specs.rb +74 -0
  78. data/testing/rspec/spec/line_filterable_specs.rb +52 -0
  79. data/testing/rspec/spec/map_reduce_spec.rb +135 -0
  80. data/testing/rspec/spec/model_query_spec.rb +49 -0
  81. data/testing/rspec/spec/multiple_queries_spec.rb +24 -0
  82. data/testing/rspec/spec/name_filterable_specs.rb +52 -0
  83. data/testing/rspec/spec/queriable_specs.rb +45 -0
  84. data/testing/rspec/spec/repository_spec.rb +82 -0
  85. data/testing/rspec/spec/select_feature_dsl_spec.rb +114 -0
  86. data/testing/rspec/spec/select_scen_outline_dsl_spec.rb +234 -0
  87. data/testing/rspec/spec/select_scenario_dsl_spec.rb +132 -0
  88. data/testing/rspec/spec/spec_helper.rb +42 -0
  89. data/testing/rspec/spec/tag_filterable_specs.rb +107 -0
  90. metadata +170 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 288eac18d6d8ed4eeb202c52abc6087b811c52da
4
- data.tar.gz: caae2839ce9f847f7bdcb98ae6b4200b79dec243
3
+ metadata.gz: 7723f8638c180e1ad2215a3912db8979a12b8722
4
+ data.tar.gz: 93cf6e70f784983ae672ff87a73616495e115d59
5
5
  SHA512:
6
- metadata.gz: 042ea7bee70217efbacd33eb7426269a43893a74fdf7f6230a75ab50e36acbd7b0cb1f7893c6079ee524160d57ec9e8ac0f5a6197688005aa57999d0ff311c04
7
- data.tar.gz: e010fbf5f25a61123a40a0d7f0cfbdde84ea187f9282c4ba305b041076c44ed3084e51f344733364b9aeef8236583141e8ad6b990226c16c5a88269acd5a9b88
6
+ metadata.gz: 588e74d98dbd1d7c5a8cf8331d45abc32ff1005ac8503c78e985f88b14f88baade72ddf6c9cdb0e70b81127e287e681e4749dc655ff3c04c973074cbd405a987
7
+ data.tar.gz: 6e83c073cadd6e57bfd6f4b28ba111f262e6e1ac11563e793e8e6751dddbfdbacb2f33b62c033940c0eee01d6d1f41004db5b9b03a23d96ebf3d5f13431ad3b2
data/lib/cql.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'cuke_modeler'
2
2
  require 'cql/map_reduce'
3
+ require 'cql/queriable'
3
4
 
4
5
  module CQL
5
6
 
@@ -59,7 +60,7 @@ module CQL
59
60
  end
60
61
 
61
62
  def determine_value(element, attribute, index)
62
- original_value = attribute.is_a?(Symbol) ? special_value(element, attribute) : element.send(attribute)
63
+ original_value = attribute.is_a?(Symbol) ? determine_special_value(element, attribute) : determine_normal_value(element, attribute)
63
64
 
64
65
  if @value_transforms
65
66
  value = mapped_attribute(@value_transforms, attribute, index)
@@ -69,10 +70,10 @@ module CQL
69
70
  value || original_value
70
71
  end
71
72
 
72
- def special_value(element, attribute)
73
+ def determine_special_value(element, attribute)
73
74
  # todo - Not sure what other special values to have but this could be expanded upon later.
74
75
  case attribute
75
- when :self
76
+ when :self, :model
76
77
  val = element
77
78
  else
78
79
  raise(ArgumentError, ":#{attribute} is not a valid attribute for selection.")
@@ -81,6 +82,14 @@ module CQL
81
82
  val
82
83
  end
83
84
 
85
+ def determine_normal_value(element, attribute)
86
+ if element.respond_to?(attribute)
87
+ element.send(attribute)
88
+ else
89
+ raise(ArgumentError, "'#{attribute}' is not a valid attribute for selection from a '#{element.class}'.")
90
+ end
91
+ end
92
+
84
93
  def mapped_attribute(mappings, attribute, location)
85
94
  case
86
95
  when mappings.is_a?(Array)
@@ -146,22 +155,20 @@ module CQL
146
155
 
147
156
  class Repository
148
157
 
158
+ include Queriable
159
+
160
+
149
161
  def initialize(repository_root)
150
162
  case
151
163
  when repository_root.is_a?(String)
152
- @target_directory = CukeModeler::Directory.new(repository_root)
164
+ root = CukeModeler::Directory.new(repository_root)
153
165
  when repository_root.class.to_s =~ /CukeModeler/
154
- @target_directory = repository_root
166
+ root = repository_root
155
167
  else
156
168
  raise(ArgumentError, "Don't know how to make a repository from a #{repository_root.class}")
157
169
  end
158
- end
159
-
160
- def query &block
161
- # A quick 'deep clone'
162
- new_repo = Marshal::load(Marshal.dump(@target_directory))
163
170
 
164
- Query.new(new_repo, &block).data
171
+ @query_root = root
165
172
  end
166
173
 
167
174
  end
@@ -53,8 +53,20 @@ module CQL
53
53
  def with(*conditions, &block)
54
54
  @filters ||= []
55
55
 
56
- @filters << block if block
57
- @filters.concat(conditions)
56
+ @filters << {:negate => false, :filter => block} if block
57
+ conditions.each do |condition|
58
+ @filters << {:negate => false, :filter => condition}
59
+ end
60
+ end
61
+
62
+ #without clause
63
+ def without(*conditions, &block)
64
+ @filters ||= []
65
+
66
+ @filters << {:negate => true, :filter => block} if block
67
+ conditions.each do |condition|
68
+ @filters << {:negate => true, :filter => condition}
69
+ end
58
70
  end
59
71
 
60
72
  class Comparison
@@ -15,8 +15,10 @@ module CQL
15
15
  }
16
16
  end
17
17
 
18
- def execute objects
19
- objects.find_all { |object| has_tags?(object, tags) }
18
+ def execute(objects, negate)
19
+ method = negate ? :reject : :select
20
+
21
+ objects.send(method) { |object| has_tags?(object, tags) }
20
22
  end
21
23
 
22
24
  end
@@ -48,8 +50,10 @@ module CQL
48
50
  @comparison = comparison
49
51
  end
50
52
 
51
- def execute input
52
- input.find_all do |object|
53
+ def execute(input, negate)
54
+ method = negate ? :reject : :select
55
+
56
+ input.send(method) do |object|
53
57
  type_count(object).send(comparison.operator, comparison.amount)
54
58
  end
55
59
  end
@@ -58,8 +62,10 @@ module CQL
58
62
 
59
63
  class NameFilter < ContentMatchFilter
60
64
 
61
- def execute(input)
62
- input.find_all do |object|
65
+ def execute(input, negate)
66
+ method = negate ? :reject : :select
67
+
68
+ input.send(method) do |object|
63
69
  content_match?([object.name])
64
70
  end
65
71
  end
@@ -15,28 +15,42 @@ module CQL
15
15
 
16
16
  if filters
17
17
  filters.each do |filter|
18
+ negate = filter[:negate]
19
+ filter = filter[:filter]
20
+
21
+ # Non-targeted filter, will apply to all objects
18
22
  if filter.is_a?(Proc)
19
- gathered_objects = filter_with_proc(gathered_objects, filter)
23
+ gathered_objects = filter_with_proc(gathered_objects, filter, negate)
24
+
25
+ # Targeted filter, will only apply to certain objects
20
26
  elsif filter.is_a?(Hash)
21
27
  filter.keys.each do |filtered_class|
22
28
  clazz = determine_class(filtered_class)
23
29
 
24
30
  gathered_objects = gathered_objects.select do |object|
31
+
32
+ # A class that is targeted by the filter, so proceed with determination
25
33
  if object.is_a?(clazz)
34
+
35
+ # Block filter
26
36
  if filter[filtered_class].is_a?(Proc)
27
- filter[filtered_class].call(object)
28
- else
37
+ filter[filtered_class].call(object) && !negate
38
+
29
39
  # Must be a predefined filter otherwise
30
- !filter_with_predefined([object], filter[filtered_class]).empty?
40
+ else
41
+ !filter_with_predefined([object], filter[filtered_class], negate).empty?
31
42
  end
43
+
44
+ # Not a class that is targeted by the filter, so include it
32
45
  else
33
46
  true
34
47
  end
35
48
  end
36
49
  end
37
- else
50
+
38
51
  # Must be a predefined filter otherwise
39
- gathered_objects = filter_with_predefined(gathered_objects, filter)
52
+ else
53
+ gathered_objects = filter_with_predefined(gathered_objects, filter, negate)
40
54
  end
41
55
  end
42
56
  end
@@ -51,17 +65,21 @@ module CQL
51
65
  private
52
66
 
53
67
 
54
- def filter_with_proc(objects, filter)
55
- objects.select(&filter)
68
+ def filter_with_proc(objects, filter, negate)
69
+ if negate
70
+ objects.reject(&filter)
71
+ else
72
+ objects.select(&filter)
73
+ end
56
74
  end
57
75
 
58
- def filter_with_predefined(objects, filter)
59
- filter.execute(objects)
76
+ def filter_with_predefined(objects, filter, negate)
77
+ filter.execute(objects, negate)
60
78
  end
61
79
 
62
80
  # Recursively gathers all objects of the given class(es) found in the passed object (including itself).
63
81
  def collect_all_in(targeted_classes, current_object, accumulated_objects)
64
- accumulated_objects << current_object if targeted_classes.any? { |targeted_class| current_object.is_a?(targeted_class) }
82
+ accumulated_objects << current_object if targeted_classes.any? { |targeted_class| (targeted_class == :all) || current_object.is_a?(targeted_class) }
65
83
 
66
84
  method_for_children = Gem.loaded_specs['cuke_modeler'].version.version[/^0/] ? :contains : :children
67
85
 
@@ -0,0 +1,18 @@
1
+ # todo - add some sore of error/warning if loading with the 0.x cuke_modeler?
2
+
3
+ module CukeModeler
4
+ class Model
5
+
6
+ include CQL::Queriable
7
+
8
+ alias_method :original_initialize, :initialize
9
+
10
+
11
+ def initialize(source_text = nil)
12
+ original_initialize(source_text)
13
+
14
+ @query_root = self
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ module CQL
2
+ module Queriable
3
+
4
+ attr_accessor :query_root
5
+
6
+
7
+ def query(&block)
8
+ raise(ArgumentError, 'Query cannot be run. No query root has been set.') unless @query_root
9
+
10
+ Query.new(@query_root, &block).data
11
+ end
12
+
13
+ end
14
+ end
@@ -13,10 +13,11 @@ module CQL
13
13
 
14
14
  class LineFilter < ContentMatchFilter
15
15
 
16
- def execute(input)
16
+ def execute(input, negate)
17
+ method_for_filtering = negate ? :reject : :select
17
18
  method_for_text = Gem.loaded_specs['cuke_modeler'].version.version[/^0/] ? :base : :text
18
19
 
19
- input.find_all do |tests|
20
+ input.send(method_for_filtering) do |tests|
20
21
  raw_step_lines = tests.steps.map { |step| step.send(method_for_text) }
21
22
 
22
23
  content_match?(raw_step_lines)
@@ -1,3 +1,3 @@
1
1
  module CQL
2
- VERSION = '1.2.1'
2
+ VERSION = '1.3.0'
3
3
  end
@@ -0,0 +1,42 @@
1
+ module CukeModeler
2
+ class CqlTestModel
3
+
4
+ attr_accessor :attribute_1
5
+ attr_accessor :attribute_2
6
+ attr_accessor :attribute_3
7
+
8
+ def children
9
+ @children ||= []
10
+
11
+ @children
12
+ end
13
+
14
+
15
+ # For cuke_modeler 0.x compatibility
16
+ alias_method :contains, :children
17
+
18
+ end
19
+
20
+ end
21
+
22
+ # Just a similarly named class for testing shorthand name matching
23
+ module CukeModeler
24
+ class CqlTestModels
25
+
26
+ attr_accessor :attribute_1
27
+ attr_accessor :attribute_2
28
+ attr_accessor :attribute_3
29
+
30
+ def children
31
+ @children ||= []
32
+
33
+ @children
34
+ end
35
+
36
+
37
+ # For cuke_modeler 0.x compatibility
38
+ alias_method :contains, :children
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,136 @@
1
+ Feature: 'as' clause'
2
+
3
+ The *as* clause allows you to change the keys under which the model attributes specified by the *select* clause will be gathered. Key renaming can be done as a list of new names that are applied in order or as a mapping of specific keys to their new names.
4
+
5
+ Sample usage:
6
+ cql_repo.query do
7
+ select name
8
+ as title
9
+ from features
10
+ end
11
+
12
+ This will return a list of all of the feature names but under the key of 'title' instead of 'name'.
13
+
14
+ This clause can be repeated multiple times. When using lists of names, the arguments for successive clauses are simply added to the previous arguments. When using mapped names, the mappings are likewise combined. If the same key is mapped more than once, the mappings are tracked separately such that they can be applied to different instances of attribute retrieval (see examples below).
15
+
16
+
17
+ Background: A sample Cucumber suite
18
+ Given a directory "test_directory"
19
+ And a file "test_directory/test_file_1.feature":
20
+ """
21
+ Feature: A test feature
22
+
23
+ Scenario: Test 1
24
+ * some steps
25
+
26
+ @special_tag
27
+ Scenario: Test 2
28
+ * some other steps
29
+
30
+ Scenario Outline: Test 3
31
+ * some steps
32
+ Examples: First examples
33
+ | param |
34
+ | value |
35
+ Examples: Second examples
36
+ | param |
37
+ | value |
38
+ """
39
+ And a repository is made from "test_directory"
40
+
41
+
42
+ Scenario: Using 'as' to change the name under which values are returned
43
+ When the following query is executed:
44
+ """
45
+ select name
46
+ as scenario_name
47
+ from scenarios, outlines
48
+ """
49
+ Then the following values are returned:
50
+ | scenario_name |
51
+ | Test 1 |
52
+ | Test 2 |
53
+ | Test 3 |
54
+
55
+ Scenario: Renaming multiple attributes
56
+ When the following query is executed:
57
+ """
58
+ select name, source_line
59
+ as scenario_name, scenario_line
60
+ from scenarios, outlines
61
+ """
62
+ Then the following values are returned:
63
+ | scenario_name | scenario_line |
64
+ | Test 1 | 3 |
65
+ | Test 2 | 7 |
66
+ | Test 3 | 10 |
67
+
68
+ Scenario: Selectively renaming attributes
69
+ When the following query is executed:
70
+ """
71
+ select name, source_line
72
+ as source_line => 'scenario_line'
73
+ from scenarios, outlines
74
+ """
75
+ Then the following values are returned:
76
+ | name | scenario_line |
77
+ | Test 1 | 3 |
78
+ | Test 2 | 7 |
79
+ | Test 3 | 10 |
80
+
81
+ Scenario: Using the 'as' clause multiple times
82
+ When the following query is executed:
83
+ """
84
+ select name, source_line
85
+ as scenario_name
86
+ as scenario_line
87
+ from scenarios, outlines
88
+ """
89
+ Then the result is the same as the result of the following query:
90
+ """
91
+ select name, source_line
92
+ as scenario_name, scenario_line
93
+ from scenarios, outlines
94
+ """
95
+ When the following query is executed:
96
+ """
97
+ select name, source_line
98
+ as name => 'scenario_name'
99
+ as source_line => 'scenario_line'
100
+ from scenarios, outlines
101
+ """
102
+ And the result is the same as the result of the following query:
103
+ """
104
+ select name, source_line
105
+ as name => 'scenario_name',
106
+ source_line => 'scenario_line'
107
+ from scenarios, outlines
108
+ """
109
+
110
+ Scenario: Renaming duplicate attributes
111
+
112
+ Sometimes you may want to select the same attribute multiple times but track it separately in the results. This can be done with both set renaming and selective renaming.
113
+
114
+ When the following query is executed:
115
+ """
116
+ select name, source_line, name
117
+ as 'name 1', scenario_line, 'name 2'
118
+ from scenarios, outlines
119
+ """
120
+ Then the following values are returned:
121
+ | name 1 | scenario_line | name 2 |
122
+ | Test 1 | 3 | Test 1 |
123
+ | Test 2 | 7 | Test 2 |
124
+ | Test 3 | 10 | Test 3 |
125
+ When the following query is executed:
126
+ """
127
+ select name, source_line, name
128
+ as name => 'name 1'
129
+ as name => 'name 2'
130
+ from scenarios, outlines
131
+ """
132
+ Then the following values are returned:
133
+ | name 1 | source_line | name 2 |
134
+ | Test 1 | 3 | Test 1 |
135
+ | Test 2 | 7 | Test 2 |
136
+ | Test 3 | 10 | Test 3 |