cql 1.4.0 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fe541449ce515566bd3a3483b42f2260829a03e1
4
- data.tar.gz: 846f80e853bef0ba8d441187370ce948e6cca50b
3
+ metadata.gz: ba9e7d8795d805ccd50924027199c698f2365df1
4
+ data.tar.gz: 0a452146ee7d5ca32764671835de2dcc486addd2
5
5
  SHA512:
6
- metadata.gz: 5f5bb7cb738155ad68f98b877d4889be5f57b69adec5c37804307aa47d29bde11c7819e3a883994e85ff3b903f636a542a575668b1cac9b299068244e3b08df6
7
- data.tar.gz: ee4e8bf2dee1d7aeb0128c65fe3001c1d21c97290b6668384d044de2066880de687a2398040616f8f000eefb6d4aed1ff269a975ae2c8f51e6769ac7364063f6
6
+ metadata.gz: 703ed14d3880d6017ea2d0699ead3aa22ffb6ee3235071fb095300db35c7754ba857225623265a39e382d8c24b0ec4ca9e547bf04ef16b4ee5fe39037fee3c16
7
+ data.tar.gz: 9cec568a459073e2bf91bea830b8365748724091592b00eb56df32037393cdad119d6de2d5c1e1a858c564832e6948ffc2e7c82dc480861ec97f26f716e447eb
data/lib/cql.rb CHANGED
@@ -1,176 +1,11 @@
1
1
  require 'cuke_modeler'
2
2
  require 'cql/map_reduce'
3
3
  require 'cql/queriable'
4
+ require 'cql/query'
5
+ require 'cql/repository'
4
6
 
5
- module CQL
6
-
7
- class Query
8
- include Dsl
9
- attr_reader :data, :what
10
-
11
- def format_data data
12
- space_data
13
-
14
- Array.new.tap do |result_array|
15
- data.each do |element|
16
- result_array << Hash.new.tap do |result|
17
- @what.each_with_index do |attribute, index|
18
- key = determine_key(attribute, index)
19
- value = determine_value(element, attribute, index)
20
-
21
- result[key] = value
22
- end
23
- end
24
- end
25
- end
26
-
27
- end
28
-
29
- def initialize(directory, &block)
30
- # Set root object
31
- @data = directory
32
-
33
- # Populate configurables from DSL block
34
- self.instance_eval(&block)
35
-
36
-
37
- raise(ArgumentError, "A query must specify a 'select' clause") unless @what
38
- raise(ArgumentError, "A query must specify a 'from' clause") unless @from
39
-
40
- warn("Multiple selections made without using an 'as' clause") unless @name_transforms || (@what.count == @what.uniq.count)
41
-
42
- # Gather relevant objects from root object and filters
43
- @data = CQL::MapReduce.gather_objects(@data, @from, @filters)
44
-
45
- # Extract properties from gathered objects
46
- @data = format_output(@data)
47
- end
48
-
49
-
50
- private
51
-
52
-
53
- def format_output(data)
54
- format_data(data)
55
- end
56
-
57
- def determine_key(attribute, index)
58
- key = mapped_attribute(@name_transforms, attribute, index) if @name_transforms
59
-
60
- key || attribute
61
- end
62
-
63
- def determine_value(element, attribute, index)
64
- original_value = attribute.is_a?(Symbol) ? determine_special_value(element, attribute) : determine_normal_value(element, attribute)
65
-
66
- if @value_transforms
67
- value = mapped_attribute(@value_transforms, attribute, index)
68
- value = value.call(original_value) if value.is_a?(Proc)
69
- end
70
-
71
- value || original_value
72
- end
73
7
 
74
- def determine_special_value(element, attribute)
75
- # todo - Not sure what other special values to have but this could be expanded upon later.
76
- case attribute
77
- when :self, :model
78
- val = element
79
- else
80
- raise(ArgumentError, ":#{attribute} is not a valid attribute for selection.")
81
- end
8
+ # The top level namespace for CQL related code.
82
9
 
83
- val
84
- end
85
-
86
- def determine_normal_value(element, attribute)
87
- if element.respond_to?(attribute)
88
- element.send(attribute)
89
- else
90
- raise(ArgumentError, "'#{attribute}' is not a valid attribute for selection from a '#{element.class}'.")
91
- end
92
- end
93
-
94
- def mapped_attribute(mappings, attribute, location)
95
- case
96
- when mappings.is_a?(Array)
97
- value = mappings[location]
98
- when mappings.is_a?(Hash)
99
- if mappings[attribute]
100
- value = mappings[attribute][location]
101
- end
102
- else
103
- # todo - add error message
104
- end
105
-
106
- value
107
- end
108
-
109
- def space_data
110
- space_renamings
111
- space_transforms
112
- end
113
-
114
- def space_renamings
115
- if @name_transforms.is_a?(Hash)
116
- new_names = {}
117
-
118
- @name_transforms.each_pair do |key, value|
119
- new_names[key] = []
120
-
121
- @what.each do |attribute|
122
- if attribute == key
123
- new_names[key] << value.shift
124
- else
125
- new_names[key] << nil
126
- end
127
- end
128
- end
129
-
130
- @name_transforms = new_names
131
- end
132
- end
133
-
134
- def space_transforms
135
- if @value_transforms.is_a?(Hash)
136
- new_values = {}
137
-
138
- @value_transforms.each_pair do |key, value|
139
- new_values[key] = []
140
-
141
- @what.each do |attribute|
142
- if attribute == key
143
- new_values[key] << value.shift
144
- else
145
- new_values[key] << nil
146
- end
147
- end
148
- end
149
-
150
- @value_transforms = new_values
151
- end
152
- end
153
-
154
- end
155
-
156
-
157
- class Repository
158
-
159
- include Queriable
160
-
161
-
162
- def initialize(repository_root)
163
- case
164
- when repository_root.is_a?(String)
165
- root = CukeModeler::Directory.new(repository_root)
166
- when repository_root.class.to_s =~ /CukeModeler/
167
- root = repository_root
168
- else
169
- raise(ArgumentError, "Don't know how to make a repository from a #{repository_root.class}")
170
- end
171
-
172
- @query_root = root
173
- end
174
-
175
- end
10
+ module CQL
176
11
  end
@@ -1,10 +1,16 @@
1
1
  module CQL
2
+
3
+ # The Domain Specific Language used for performing queries.
4
+
2
5
  module Dsl
3
6
 
7
+
8
+ # Any undefined method is assumed to mean its String equivalent, thus allowing a more convenient query syntax.
4
9
  def method_missing(method_name)
5
10
  method_name.to_s
6
11
  end
7
12
 
13
+ # Adds a *transform* clause to the query. See the corresponding Cucumber documentation for details.
8
14
  def transform(*attribute_transforms, &block)
9
15
  # todo - Still feels like some as/transform code duplication but I think that it would get too meta if I
10
16
  # reduced it any further. Perhaps change how the transforms are handled so that there doesn't have to be
@@ -16,13 +22,14 @@ module CQL
16
22
  add_transforms(attribute_transforms, @value_transforms)
17
23
  end
18
24
 
25
+ # Adds an *as* clause to the query. See the corresponding Cucumber documentation for details.
19
26
  def as(*name_transforms)
20
27
  prep_variable('name_transforms', name_transforms) unless @name_transforms
21
28
 
22
29
  add_transforms(name_transforms, @name_transforms)
23
30
  end
24
31
 
25
- #Select clause
32
+ # Adds a *select* clause to the query. See the corresponding Cucumber documentation for details.
26
33
  def select *what
27
34
  what = [:self] if what.empty?
28
35
 
@@ -30,17 +37,19 @@ module CQL
30
37
  @what.concat(what)
31
38
  end
32
39
 
40
+ # Adds a *name* filter to the query. See the corresponding Cucumber documentation for details.
33
41
  def name *args
34
42
  return 'name' if args.size == 0
35
43
  CQL::NameFilter.new args[0]
36
44
  end
37
45
 
46
+ # Adds a *line* filter to the query. See the corresponding Cucumber documentation for details.
38
47
  def line *args
39
48
  return 'line' if args.size == 0
40
49
  CQL::LineFilter.new args.first
41
50
  end
42
51
 
43
- #from clause
52
+ # Adds a *from* clause to the query. See the corresponding Cucumber documentation for details.
44
53
  def from(*targets)
45
54
  @from ||= []
46
55
 
@@ -49,7 +58,7 @@ module CQL
49
58
  @from.concat(targets)
50
59
  end
51
60
 
52
- #with clause
61
+ # Adds a *with* clause to the query. See the corresponding Cucumber documentation for details.
53
62
  def with(*conditions, &block)
54
63
  @filters ||= []
55
64
 
@@ -59,7 +68,7 @@ module CQL
59
68
  end
60
69
  end
61
70
 
62
- #without clause
71
+ # Adds a *without* clause to the query. See the corresponding Cucumber documentation for details.
63
72
  def without(*conditions, &block)
64
73
  @filters ||= []
65
74
 
@@ -69,6 +78,7 @@ module CQL
69
78
  end
70
79
  end
71
80
 
81
+ # Not a part of the public API. Subject to change at any time.
72
82
  class Comparison
73
83
  attr_accessor :operator, :amount
74
84
 
@@ -79,48 +89,62 @@ module CQL
79
89
 
80
90
  end
81
91
 
92
+ # Adds a *tc* filter to the query. See the corresponding Cucumber documentation for details.
82
93
  def tc comparison
83
94
  TagCountFilter.new 'tc', comparison
84
95
  end
85
96
 
97
+ # Adds a *lc* filter to the query. See the corresponding Cucumber documentation for details.
86
98
  def lc comparison
87
99
  CQL::SsoLineCountFilter.new('lc', comparison)
88
100
  end
89
101
 
102
+ # Adds an *ssoc* filter to the query. See the corresponding Cucumber documentation for details.
90
103
  def ssoc comparison
91
104
  TestCountFilter.new([CukeModeler::Scenario, CukeModeler::Outline], comparison)
92
105
  end
93
106
 
107
+ # Adds an *sc* filter to the query. See the corresponding Cucumber documentation for details.
94
108
  def sc comparison
95
109
  TestCountFilter.new([CukeModeler::Scenario], comparison)
96
110
  end
97
111
 
112
+ # Adds an *soc* filter to the query. See the corresponding Cucumber documentation for details.
98
113
  def soc comparison
99
114
  TestCountFilter.new([CukeModeler::Outline], comparison)
100
115
  end
101
116
 
117
+ # Adds a *gt* filter operator to the query. See the corresponding Cucumber documentation for details.
102
118
  def gt amount
103
119
  Comparison.new '>', amount
104
120
  end
105
121
 
122
+ # Adds a *gte* filter operator to the query. See the corresponding Cucumber documentation for details.
106
123
  def gte amount
107
124
  Comparison.new '>=', amount
108
125
  end
109
126
 
127
+ # Adds an *lt* filter operator to the query. See the corresponding Cucumber documentation for details.
110
128
  def lt amount
111
129
  Comparison.new '<', amount
112
130
  end
113
131
 
132
+ # Adds an *lte* filter operator to the query. See the corresponding Cucumber documentation for details.
114
133
  def lte amount
115
134
  Comparison.new '<=', amount
116
135
  end
117
136
 
137
+ # Adds a *tags* filter to the query. See the corresponding Cucumber documentation for details.
118
138
  def tags *tags
119
139
  return "tags" if tags.size == 0
120
140
 
121
141
  TagFilter.new tags
122
142
  end
123
143
 
144
+
145
+ private
146
+
147
+
124
148
  def translate_shorthand(where)
125
149
  where.split('_').map(&:capitalize).join
126
150
  end
@@ -3,8 +3,10 @@ require 'cql/filters'
3
3
 
4
4
  module CQL
5
5
 
6
+ # Not a part of the public API. Subject to change at any time.
6
7
  class TestCountFilter < TypeCountFilter
7
8
 
9
+ # Counts the numbers of tests of a certain type
8
10
  def type_count(feature)
9
11
  feature.tests.find_all { |test| types.include?(test.class) }.size
10
12
  end
@@ -1,5 +1,6 @@
1
1
  module CQL
2
2
 
3
+ # Not a part of the public API. Subject to change at any time.
3
4
  class TagFilter
4
5
  attr_reader :tags
5
6
 
@@ -15,6 +16,7 @@ module CQL
15
16
  }
16
17
  end
17
18
 
19
+ # Filters the input models so that only the desired ones are returned
18
20
  def execute(objects, negate)
19
21
  method = negate ? :reject : :select
20
22
 
@@ -23,6 +25,7 @@ module CQL
23
25
 
24
26
  end
25
27
 
28
+ # Not a part of the public API. Subject to change at any time.
26
29
  class ContentMatchFilter
27
30
  attr_reader :pattern
28
31
 
@@ -42,6 +45,7 @@ module CQL
42
45
 
43
46
  end
44
47
 
48
+ # Not a part of the public API. Subject to change at any time.
45
49
  class TypeCountFilter
46
50
  attr_reader :types, :comparison
47
51
 
@@ -50,6 +54,8 @@ module CQL
50
54
  @comparison = comparison
51
55
  end
52
56
 
57
+ # Not a part of the public API. Subject to change at any time.
58
+ # Filters the input models so that only the desired ones are returned
53
59
  def execute(input, negate)
54
60
  method = negate ? :reject : :select
55
61
 
@@ -60,8 +66,10 @@ module CQL
60
66
 
61
67
  end
62
68
 
69
+ # Not a part of the public API. Subject to change at any time.
63
70
  class NameFilter < ContentMatchFilter
64
71
 
72
+ # Filters the input models so that only the desired ones are returned
65
73
  def execute(input, negate)
66
74
  method = negate ? :reject : :select
67
75
 
@@ -72,8 +80,11 @@ module CQL
72
80
 
73
81
  end
74
82
 
83
+
84
+ # Not a part of the public API. Subject to change at any time.
75
85
  class TagCountFilter < TypeCountFilter
76
86
 
87
+ # Counts the numbers of tags on a test
77
88
  def type_count(test)
78
89
  test.tags.size
79
90
  end
@@ -6,10 +6,13 @@ require 'cql/dsl'
6
6
 
7
7
  module CQL
8
8
 
9
+ # Not a part of the public API. Subject to change at any time.
9
10
  class MapReduce
10
11
 
11
12
  extend Dsl
12
13
 
14
+
15
+ # Recursively gathers all models that match the given targets and filters
13
16
  def self.gather_objects(current_object, target_classes, filters)
14
17
  gathered_objects = Array.new.tap { |gathered_objects| collect_all_in(target_classes, current_object, gathered_objects) }
15
18
 
@@ -1,13 +1,19 @@
1
- # todo - add some sore of error/warning if loading with the 0.x cuke_modeler?
1
+ # todo - add some sort of error/warning if loading with the 0.x cuke_modeler?
2
2
 
3
3
  module CukeModeler
4
+
5
+ # A monkey patch that allows models to be queried directly by having them use this gem's query module.
6
+
4
7
  class Model
5
8
 
6
9
  include CQL::Queriable
7
10
 
11
+
12
+ # Hanging on to the original method so that it can be invoked and thus ensure that all of the normal, un-patched behavior occurs
8
13
  alias_method :original_initialize, :initialize
9
14
 
10
15
 
16
+ # Sets itself as the model's *query_root*. Otherwise, as per the un-patched method.
11
17
  def initialize(source_text = nil)
12
18
  original_initialize(source_text)
13
19
 
@@ -1,9 +1,14 @@
1
1
  module CQL
2
+
3
+ # A mix-in module containing methods used by objects that want to be able to run queries against objects (often themselves).
4
+
2
5
  module Queriable
3
6
 
4
- attr_accessor :query_root
7
+ # The object against which the query will be run.
8
+ attr_accessor :query_root # todo - deprecate this such that queries are always performed against *self*
5
9
 
6
10
 
11
+ # Performs a query against the current *query_root*
7
12
  def query(&block)
8
13
  raise(ArgumentError, 'Query cannot be run. No query root has been set.') unless @query_root
9
14
 
@@ -0,0 +1,154 @@
1
+ module CQL
2
+
3
+ # Not a part of the public API. Subject to change at any time.
4
+ class Query
5
+
6
+ include Dsl
7
+
8
+ attr_reader :data, :what
9
+
10
+
11
+ def initialize(directory, &block)
12
+ # Set root object
13
+ @data = directory
14
+
15
+ # Populate configurables from DSL block
16
+ self.instance_eval(&block)
17
+
18
+
19
+ raise(ArgumentError, "A query must specify a 'select' clause") unless @what
20
+ raise(ArgumentError, "A query must specify a 'from' clause") unless @from
21
+
22
+ warn("Multiple selections made without using an 'as' clause") unless @name_transforms || (@what.count == @what.uniq.count)
23
+
24
+ # Gather relevant objects from root object and filters
25
+ @data = CQL::MapReduce.gather_objects(@data, @from, @filters)
26
+
27
+ # Extract properties from gathered objects
28
+ @data = format_output(@data)
29
+ end
30
+
31
+
32
+ private
33
+
34
+
35
+ def format_output(data)
36
+ format_data(data)
37
+ end
38
+
39
+ def format_data data
40
+ space_data
41
+
42
+ Array.new.tap do |result_array|
43
+ data.each do |element|
44
+ result_array << Hash.new.tap do |result|
45
+ @what.each_with_index do |attribute, index|
46
+ key = determine_key(attribute, index)
47
+ value = determine_value(element, attribute, index)
48
+
49
+ result[key] = value
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ def determine_key(attribute, index)
57
+ key = mapped_attribute(@name_transforms, attribute, index) if @name_transforms
58
+
59
+ key || attribute
60
+ end
61
+
62
+ def determine_value(element, attribute, index)
63
+ original_value = attribute.is_a?(Symbol) ? determine_special_value(element, attribute) : determine_normal_value(element, attribute)
64
+
65
+ if @value_transforms
66
+ value = mapped_attribute(@value_transforms, attribute, index)
67
+ value = value.call(original_value) if value.is_a?(Proc)
68
+ end
69
+
70
+ value || original_value
71
+ end
72
+
73
+ def determine_special_value(element, attribute)
74
+ # todo - Not sure what other special values to have but this could be expanded upon later.
75
+ case attribute
76
+ when :self, :model
77
+ val = element
78
+ else
79
+ raise(ArgumentError, ":#{attribute} is not a valid attribute for selection.")
80
+ end
81
+
82
+ val
83
+ end
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
+
93
+ def mapped_attribute(mappings, attribute, location)
94
+ case
95
+ when mappings.is_a?(Array)
96
+ value = mappings[location]
97
+ when mappings.is_a?(Hash)
98
+ if mappings[attribute]
99
+ value = mappings[attribute][location]
100
+ end
101
+ else
102
+ raise(ArgumentError, "Unknown mapping type '#{mappings.class}'")
103
+ end
104
+
105
+ value
106
+ end
107
+
108
+ def space_data
109
+ space_renamings
110
+ space_transforms
111
+ end
112
+
113
+ def space_renamings
114
+ if @name_transforms.is_a?(Hash)
115
+ new_names = {}
116
+
117
+ @name_transforms.each_pair do |key, value|
118
+ new_names[key] = []
119
+
120
+ @what.each do |attribute|
121
+ if attribute == key
122
+ new_names[key] << value.shift
123
+ else
124
+ new_names[key] << nil
125
+ end
126
+ end
127
+ end
128
+
129
+ @name_transforms = new_names
130
+ end
131
+ end
132
+
133
+ def space_transforms
134
+ if @value_transforms.is_a?(Hash)
135
+ new_values = {}
136
+
137
+ @value_transforms.each_pair do |key, value|
138
+ new_values[key] = []
139
+
140
+ @what.each do |attribute|
141
+ if attribute == key
142
+ new_values[key] << value.shift
143
+ else
144
+ new_values[key] << nil
145
+ end
146
+ end
147
+ end
148
+
149
+ @value_transforms = new_values
150
+ end
151
+ end
152
+
153
+ end
154
+ end
@@ -0,0 +1,24 @@
1
+ module CQL
2
+
3
+ # A repository is a group of models. See the corresponding Cucumber documentation for details.
4
+
5
+ class Repository
6
+
7
+ include Queriable
8
+
9
+
10
+ def initialize(repository_root)
11
+ case
12
+ when repository_root.is_a?(String)
13
+ root = CukeModeler::Directory.new(repository_root)
14
+ when repository_root.class.to_s =~ /CukeModeler/
15
+ root = repository_root
16
+ else
17
+ raise(ArgumentError, "Don't know how to make a repository from a #{repository_root.class}")
18
+ end
19
+
20
+ @query_root = root
21
+ end
22
+
23
+ end
24
+ end
@@ -3,16 +3,20 @@ require 'cql/filters'
3
3
 
4
4
  module CQL
5
5
 
6
+ # Not a part of the public API. Subject to change at any time.
6
7
  class SsoLineCountFilter < TypeCountFilter
7
8
 
9
+ # Counts the numbers of steps on a test
8
10
  def type_count(test)
9
11
  test.steps.size
10
12
  end
11
13
 
12
14
  end
13
15
 
16
+ # Not a part of the public API. Subject to change at any time.
14
17
  class LineFilter < ContentMatchFilter
15
18
 
19
+ # Filters the input models so that only the desired ones are returned
16
20
  def execute(input, negate)
17
21
  method_for_filtering = negate ? :reject : :select
18
22
  method_for_text = Gem.loaded_specs['cuke_modeler'].version.version[/^0/] ? :base : :text
@@ -1,3 +1,4 @@
1
1
  module CQL
2
- VERSION = '1.4.0'
2
+ # The current version of the gem
3
+ VERSION = '1.4.1'
3
4
  end
@@ -2,12 +2,14 @@ Feature: 'as' clause'
2
2
 
3
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
4
 
5
- Sample usage:
6
- cql_repo.query do
7
- select name
8
- as title
9
- from features
10
- end
5
+ Sample usage:
6
+ ````
7
+ cql_repo.query do
8
+ select name
9
+ as title
10
+ from features
11
+ end
12
+ ````
11
13
 
12
14
  This will return a list of all of the feature names but under the key of 'title' instead of 'name'.
13
15
 
@@ -15,8 +17,8 @@ Feature: 'as' clause'
15
17
 
16
18
 
17
19
  Background: A sample Cucumber suite
18
- Given a directory "test_directory"
19
- And a file "test_directory/test_file_1.feature":
20
+ Given a repository to query
21
+ And the following feature has been modeled in the repository:
20
22
  """
21
23
  Feature: A test feature
22
24
 
@@ -36,7 +38,6 @@ Feature: 'as' clause'
36
38
  | param |
37
39
  | value |
38
40
  """
39
- And a repository is made from "test_directory"
40
41
 
41
42
 
42
43
  Scenario: Using 'as' to change the name under which values are returned
@@ -4,22 +4,26 @@ Feature: 'from' clause
4
4
 
5
5
  The following are some example values:
6
6
 
7
- CukeModeler::Outline (exact class)
8
- outline (singular)
9
- outlines (pluralized)
10
-
11
- Sample usage:
12
- cql_repo.query do
13
- select name
14
- from scenarios
15
- end
7
+ ````
8
+ CukeModeler::Outline # exact class
9
+ outline # singular
10
+ outlines # pluralized
11
+ ````
12
+
13
+ Sample usage:
14
+ ````
15
+ cql_repo.query do
16
+ select name
17
+ from scenarios
18
+ end
19
+ ````
16
20
 
17
21
  This clause can be repeated multiple times. The arguments for successive clauses are simply added to the previous arguments.
18
22
 
19
23
 
20
24
  Background: A sample Cucumber suite
21
- Given a directory "test_directory"
22
- And a file "test_directory/test_file_1.feature":
25
+ Given a repository to query
26
+ And the following feature has been modeled in the repository:
23
27
  """
24
28
  Feature: A test feature
25
29
 
@@ -39,7 +43,6 @@ Feature: 'from' clause
39
43
  | param |
40
44
  | value |
41
45
  """
42
- And a repository is made from "test_directory"
43
46
 
44
47
 
45
48
  Scenario: Using 'from' to specify what kind of objects from which to return attributes
@@ -2,18 +2,20 @@ Feature: 'select' clause
2
2
 
3
3
  The *select* clause specifies what attributes will be retrieved from the models specified by the *from* clause. Multiple values can be given and they are delimited by a comma. The *select* clause can take any method to which the objects specified by *from* know how to respond. The clause can also be given a special identifier in order to return the underlying models themselves instead of their attributes. If no attributes are specified then the underlying model will be returned instead, just as if the special identifier had been used (it is simply an alternate syntax and may look nicer in some queries).
4
4
 
5
- Sample usage:
6
- cql_repo.query do
7
- select name, tags, description_text
8
- from features
9
- end
5
+ Sample usage:
6
+ ````
7
+ cql_repo.query do
8
+ select name, tags, description_text
9
+ from features
10
+ end
11
+ ````
10
12
 
11
13
  This clause can be repeated multiple times. The arguments for successive clauses are simply added to the previous arguments.
12
14
 
13
15
 
14
- Background: A sample Cucumber suite
15
- Given a directory "test_directory"
16
- And a file "test_directory/test_file_1.feature":
16
+ Background: Repository with models
17
+ Given a repository to query
18
+ And the following feature has been modeled in the repository:
17
19
  """
18
20
  Feature: A test feature
19
21
 
@@ -33,7 +35,6 @@ Feature: 'select' clause
33
35
  | param |
34
36
  | value |
35
37
  """
36
- And a repository is made from "test_directory"
37
38
 
38
39
 
39
40
  Scenario: Using 'select' to specify which attributes of an object to return
@@ -2,20 +2,22 @@ Feature: 'transform' clause
2
2
 
3
3
  The *transform* clause allows you to change the values of the attributes specified by the *select* clause after they are gathered. Value transforming can be done as a list of transformation blocks that are applied in order or as a mapping of specific keys and their transformations.
4
4
 
5
- Sample usage:
6
- cql_repo.query do
7
- select name
8
- transform { |name| name.upcase }
9
- from features
10
- end
5
+ Sample usage:
6
+ ````
7
+ cql_repo.query do
8
+ select name
9
+ transform { |name| name.upcase }
10
+ from features
11
+ end
12
+ ````
11
13
 
12
14
  This will return a list of all of the feature names but with all of their names upcased.
13
15
 
14
16
  This clause can be repeated multiple times. When using lists of transforms, the arguments for successive clauses are simply added to the previous arguments. When using mapped transforms, 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
17
 
16
18
  Background: A sample Cucumber suite
17
- Given a directory "test_directory"
18
- And a file "test_directory/test_file_1.feature":
19
+ Given a repository to query
20
+ And the following feature has been modeled in the repository:
19
21
  """
20
22
  Feature: A test feature
21
23
 
@@ -35,7 +37,6 @@ Feature: 'transform' clause
35
37
  | param |
36
38
  | value |
37
39
  """
38
- And a repository is made from "test_directory"
39
40
 
40
41
 
41
42
  Scenario: Using 'transform' to change values after they are gathered
@@ -3,13 +3,15 @@ Feature: 'with' clause
3
3
 
4
4
  The *with* clause specifies filter conditions that will reduce the number of things targeted by the *from* clause. The *with* clause can take one or more blocks that will filter out any object for which the block does not evaluate to true (using 'without' instead of 'with' will have the opposite effect). Alternatively, mappings of specific *from* targets to their respective filtering blocks can be provided. The *with* clause can also take predefined filters (detailed below).
5
5
 
6
- Sample usage:
7
- cql_repo.query do
8
- select name, tags, description_text
9
- from features
10
- with { |feature| feature.name =~ /foo/ }
11
- with tc lt 3
12
- end
6
+ Sample usage:
7
+ ````
8
+ cql_repo.query do
9
+ select name, tags, description_text
10
+ from features
11
+ with { |feature| feature.name =~ /foo/ }
12
+ with tc lt 3
13
+ end
14
+ ````
13
15
 
14
16
  This clause can be repeated multiple times. The arguments for successive clauses are simply added to the previous arguments.
15
17
 
@@ -2,22 +2,25 @@ Feature: DSL
2
2
 
3
3
  The cql gem uses a DSL to specify queries on a repository object that holds the models which represent a Cucumber test suite. The DSL can query for any attribute that is available on the underlying models.
4
4
 
5
- Sample usage:
6
- cql_repo.query do
7
- select name, source_line
8
- from features
9
- end
5
+ Sample usage:
6
+ ````
7
+ cql_repo.query do
8
+ select name, source_line
9
+ from features
10
+ end
11
+ ````
10
12
 
11
13
  Query results are returned as a list of attribute mappings for all of the models found in the repository. The sample query above might return:
12
14
 
13
- [{'name' => 'Feature 1', 'source_line' => 1},
14
- {'name' => 'Feature 2', 'source_line' => 3},
15
- {'name' => 'Feature 3', 'source_line' => 10}]
16
-
15
+ ````
16
+ [{'name' => 'Feature 1', 'source_line' => 1},
17
+ {'name' => 'Feature 2', 'source_line' => 3},
18
+ {'name' => 'Feature 3', 'source_line' => 10}]
19
+ ````
17
20
 
18
21
  Background: A sample Cucumber suite
19
- Given a directory "test_directory"
20
- And a file "test_directory/test_file_1.feature":
22
+ Given a repository to query
23
+ And the following feature has been modeled in the repository:
21
24
  """
22
25
  Feature: A test feature
23
26
 
@@ -37,7 +40,7 @@ Feature: DSL
37
40
  | param |
38
41
  | value |
39
42
  """
40
- And a repository is made from "test_directory"
43
+
41
44
 
42
45
  Scenario: Automatic string conversion
43
46
 
@@ -1,17 +1,5 @@
1
1
  Given(/^a directory "([^"]*)"$/) do |partial_directory_path|
2
- directory_path = partial_directory_path.include?('path/to') ? process_path(partial_directory_path) : "#{@default_file_directory}/#{partial_directory_path}"
3
-
4
- FileUtils.mkpath(directory_path) unless File.exists?(directory_path)
5
- end
6
-
7
- And(/^a file "([^"]*)":$/) do |partial_file_path, file_text|
8
- File.open("#{@default_file_directory}/#{partial_file_path}", 'w') { |file| file.write file_text }
9
- end
10
-
11
- And(/^a repository is made from "([^"]*)"$/) do |partial_path|
12
- repo_path = "#{@default_file_directory}/#{partial_path}"
13
-
14
- @repository = CQL::Repository.new(repo_path)
2
+ create_path(partial_directory_path)
15
3
  end
16
4
 
17
5
  Given(/^the models provided by CukeModeler$/) do
@@ -41,7 +41,7 @@ Then(/^the result is the same as the result of the following query:$/) do |query
41
41
  end
42
42
 
43
43
  Then(/^the following code executes without error:$/) do |code_text|
44
- code_text = process_path(code_text)
44
+ code_text.sub!('path/to', @temp_dir)
45
45
 
46
46
  expect { eval(code_text) }.to_not raise_error
47
47
  end
@@ -3,22 +3,22 @@ unless RUBY_VERSION.to_s < '1.9.0'
3
3
  SimpleCov.command_name('cql-cucumber')
4
4
  end
5
5
 
6
+ require 'tmpdir'
6
7
 
7
8
  require 'cql'
8
9
  require 'cql/model_dsl'
9
10
 
10
11
 
11
- Before do
12
- @default_file_directory = "#{File.dirname(__FILE__)}/../temp_files"
13
-
14
- FileUtils.mkdir(@default_file_directory)
15
- end
16
-
17
12
  After do
18
- FileUtils.remove_dir(@default_file_directory, true)
13
+ FileUtils.remove_dir(@temp_dir, true) if @temp_dir
19
14
  end
20
15
 
21
16
 
22
- def process_path(path)
23
- path.sub('path/to', @default_file_directory)
17
+ def create_path(path)
18
+ @temp_dir ||= Dir.mktmpdir
19
+ path = path.sub('path/to/', "#{@temp_dir}/")
20
+
21
+ Dir.mkdir(path)
22
+
23
+ path
24
24
  end
@@ -20,6 +20,7 @@ if RUBY_VERSION =~ /^1\./
20
20
  gem 'tins', '< 1.7' # The 'tins' gem requires Ruby 2.x on/after this version
21
21
  gem 'json', '< 2.0' # The 'json' gem drops pre-Ruby 2.x support on/after this version
22
22
  gem 'term-ansicolor', '< 1.4' # The 'term-ansicolor' gem requires Ruby 2.x on/after this version
23
+ gem 'unf_ext', '< 0.0.7.3' # Requires Ruby 2.x on/after this version
23
24
 
24
25
  if RbConfig::CONFIG['host_os'].downcase =~ /mswin|msys|mingw32/
25
26
  gem 'ffi', '< 1.9.15' # The 'ffi' gem, for Windows, requires Ruby 2.x on/after this version
@@ -20,6 +20,7 @@ if RUBY_VERSION =~ /^1\./
20
20
  gem 'tins', '< 1.7' # The 'tins' gem requires Ruby 2.x on/after this version
21
21
  gem 'json', '< 2.0' # The 'json' gem drops pre-Ruby 2.x support on/after this version
22
22
  gem 'term-ansicolor', '< 1.4' # The 'term-ansicolor' gem requires Ruby 2.x on/after this version
23
+ gem 'unf_ext', '< 0.0.7.3' # Requires Ruby 2.x on/after this version
23
24
 
24
25
  if RbConfig::CONFIG['host_os'].downcase =~ /mswin|msys|mingw32/
25
26
  gem 'ffi', '< 1.9.15' # The 'ffi' gem, for Windows, requires Ruby 2.x on/after this version
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cql
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Kessler
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-04-10 00:00:00.000000000 Z
12
+ date: 2017-06-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: cuke_modeler
@@ -31,14 +31,14 @@ dependencies:
31
31
  requirements:
32
32
  - - "<"
33
33
  - !ruby/object:Gem::Version
34
- version: 12.0.0
34
+ version: 13.0.0
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - "<"
40
40
  - !ruby/object:Gem::Version
41
- version: 12.0.0
41
+ version: 13.0.0
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: rspec
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -153,6 +153,8 @@ files:
153
153
  - lib/cql/map_reduce.rb
154
154
  - lib/cql/model_dsl.rb
155
155
  - lib/cql/queriable.rb
156
+ - lib/cql/query.rb
157
+ - lib/cql/repository.rb
156
158
  - lib/cql/sso_filters.rb
157
159
  - lib/cql/version.rb
158
160
  - testing/cql_test_model.rb