set_builder 2.0.0.beta3 → 2.0.0.beta4
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/assets/javascripts/set_builder.js +19 -13
- data/lib/set_builder/constraint.rb +11 -8
- data/lib/set_builder/modifier/arguments.rb +50 -0
- data/lib/set_builder/modifier/base.rb +18 -16
- data/lib/set_builder/modifiers/date_preposition.rb +8 -8
- data/lib/set_builder/modifiers/number_preposition.rb +4 -4
- data/lib/set_builder/modifiers/string_preposition.rb +8 -8
- data/lib/set_builder/parser.rb +36 -0
- data/lib/set_builder/trait.rb +2 -33
- data/lib/set_builder/version.rb +1 -1
- data/spec/unit/set_builder.spec.js +31 -6
- data/test/constraint_test.rb +36 -12
- data/test/modifier_test.rb +28 -28
- metadata +52 -27
- checksums.yaml +0 -7
@@ -30,12 +30,14 @@ var SetBuilder = (function() {
|
|
30
30
|
return _modifiers;
|
31
31
|
},
|
32
32
|
getValueMap: function(key) {
|
33
|
-
|
33
|
+
var valueMap = _value_maps[key];
|
34
|
+
return typeof valueMap == 'function' ? valueMap() : valueMap;
|
34
35
|
},
|
35
|
-
getValue: function(key, value) {
|
36
|
+
getValue: function(key, value, valueMap) {
|
37
|
+
var map = valueMap || SetBuilder.getValueMap(key);
|
36
38
|
if(Object.prototype.toString.call(value) == '[object Array]') {
|
37
39
|
var getValue = arguments.callee;
|
38
|
-
var values = value.__collect(function(value) { return getValue(key, value) });
|
40
|
+
var values = value.__collect(function(value) { return getValue(key, value, map) });
|
39
41
|
switch(values.length) {
|
40
42
|
case 0: return '';
|
41
43
|
case 1: return values[0];
|
@@ -43,9 +45,7 @@ var SetBuilder = (function() {
|
|
43
45
|
default: return values.slice(0, -1).join(', ') + ', or ' + values[values.length - 1];
|
44
46
|
}
|
45
47
|
}
|
46
|
-
|
47
|
-
var match = value.toString(),
|
48
|
-
map = SetBuilder.getValueMap(key);
|
48
|
+
var match = value.toString();
|
49
49
|
if(map) {
|
50
50
|
var pair = map.__find(function(i) { return (i[0] == match) });
|
51
51
|
return pair ? pair[1] : '(unknown)';
|
@@ -174,11 +174,16 @@ SetBuilder.Modifier = function(_name, _operator, _values, _params) {
|
|
174
174
|
}
|
175
175
|
|
176
176
|
this.toString = function() {
|
177
|
-
var words = [_operator.replace(/_/, ' ')];
|
178
|
-
|
179
|
-
|
177
|
+
var words = [_operator.replace(/_/, ' '), ' '];
|
178
|
+
var __values = _values.dup();
|
179
|
+
for(var i=0; i<_params.length; i++) {
|
180
|
+
if(_params[i][0] == 'arg') {
|
181
|
+
words.push(SetBuilder.getValue(_params[i][1], __values.shift()));
|
182
|
+
} else {
|
183
|
+
words.push(_params[i][1])
|
184
|
+
}
|
180
185
|
}
|
181
|
-
return words.join('
|
186
|
+
return words.join('');
|
182
187
|
}
|
183
188
|
|
184
189
|
};
|
@@ -247,13 +252,14 @@ SetBuilder.Modifiers = function(_modifiers) {
|
|
247
252
|
var operator = args.operator;
|
248
253
|
if(!operator) throw 'An operator name was not supplied.'
|
249
254
|
|
250
|
-
var params = this.params_for_operator(modifier_type, operator)
|
255
|
+
var params = this.params_for_operator(modifier_type, operator)
|
256
|
+
var paramsLength = params.__select(function(token) { return token[0] == 'arg' }).length;
|
251
257
|
var values = args.values;
|
252
258
|
|
253
259
|
if(!values) values = [];
|
254
260
|
if(!(values instanceof Array)) values = [values];
|
255
|
-
if(values.length !=
|
256
|
-
throw ('The operator "' + operator.toString() + '" expects ' +
|
261
|
+
if(values.length != paramsLength) {
|
262
|
+
throw ('The operator "' + operator.toString() + '" expects ' + paramsLength + ' arguments but received ' + values.length + '.');
|
257
263
|
}
|
258
264
|
|
259
265
|
return new SetBuilder.Modifier(name, operator, values, params);
|
@@ -23,7 +23,17 @@ module SetBuilder
|
|
23
23
|
@params = params
|
24
24
|
|
25
25
|
@direct_object = params[direct_object_type] if trait.requires_direct_object?
|
26
|
-
|
26
|
+
|
27
|
+
# Map supplied enum values to what the Trait has defined.
|
28
|
+
# If there are any discrepancies or missing values, fill them
|
29
|
+
# in with values that will work.
|
30
|
+
enum_values = params[:enums] || []
|
31
|
+
@enums = trait.enums.each_with_index.map do |expected_values, i|
|
32
|
+
value = enum_values[i]
|
33
|
+
value = expected_values[0] unless expected_values.include?(value)
|
34
|
+
value
|
35
|
+
end
|
36
|
+
|
27
37
|
modifiers = params.fetch(:modifiers, [])
|
28
38
|
@modifiers = trait.modifiers.each_with_index.map { |modifier, i|
|
29
39
|
modifier.new(modifiers[i] || {}) }
|
@@ -38,13 +48,6 @@ module SetBuilder
|
|
38
48
|
def errors
|
39
49
|
[].tap do |errors|
|
40
50
|
errors.push "#{direct_object_type} is blank" if direct_object_required? && direct_object.nil?
|
41
|
-
if enums.length != trait.enums.length
|
42
|
-
errors.push "should have values for #{trait.enums.length} enums"
|
43
|
-
else
|
44
|
-
trait.enums.each_with_index do |expected_values, i|
|
45
|
-
errors.push "enum ##{i + 1} should be #{expected_values.map { |value| "'#{value}'" }.to_sentence(two_words_connector: " or ", last_word_connector: ", or ")}" unless expected_values.member?(enums[i])
|
46
|
-
end
|
47
|
-
end
|
48
51
|
errors.concat modifiers.flat_map(&:errors)
|
49
52
|
end
|
50
53
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "set_builder/parser"
|
2
|
+
|
3
|
+
module SetBuilder
|
4
|
+
module Modifier
|
5
|
+
class Arguments
|
6
|
+
attr_reader :arguments, :expression, :tokens
|
7
|
+
|
8
|
+
include Parser
|
9
|
+
|
10
|
+
def initialize(expression)
|
11
|
+
@expression = expression.respond_to?(:each) ? map_legacy_arguments(expression) : expression
|
12
|
+
@tokens = parse(@expression)
|
13
|
+
end
|
14
|
+
|
15
|
+
def arity
|
16
|
+
types.count
|
17
|
+
end
|
18
|
+
|
19
|
+
def types
|
20
|
+
@types ||= @tokens
|
21
|
+
.select { |token, _| token == :arg }
|
22
|
+
.map { |_, type| type }
|
23
|
+
end
|
24
|
+
|
25
|
+
def as_json(*)
|
26
|
+
tokens.map { |(token, value)| [token.to_s, value] }
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s(values)
|
30
|
+
_values = values.dup
|
31
|
+
tokens.map do |token, token_value|
|
32
|
+
if token == :arg
|
33
|
+
ValueMap.to_s(token_value, _values.shift)
|
34
|
+
else
|
35
|
+
token_value
|
36
|
+
end
|
37
|
+
end.join
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def map_legacy_arguments(arguments)
|
43
|
+
_expression = arguments.map { |arg| "{#{arg}}" }.join(" ")
|
44
|
+
puts "DEPRECATED: SetBuilder::Modifier should use expression style argumenents now e.g.-> \"#{_expression}\""
|
45
|
+
_expression
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "set_builder/modifier/arguments"
|
2
|
+
|
1
3
|
module SetBuilder
|
2
4
|
module Modifier
|
3
5
|
class Base
|
@@ -43,11 +45,11 @@ module SetBuilder
|
|
43
45
|
|
44
46
|
def errors_with_values
|
45
47
|
[].tap do |errors|
|
46
|
-
|
47
|
-
if values.length !=
|
48
|
-
errors.push "wrong number of arguments; expected #{
|
48
|
+
arguments = self.class.parsed_operators[operator] || Arguments.new("")
|
49
|
+
if values.length != arguments.arity
|
50
|
+
errors.push "wrong number of arguments; expected #{arguments.arity} (#{arguments.types.join(", ")})"
|
49
51
|
else
|
50
|
-
errors.concat values.each_with_index.flat_map { |value, i| errors_with_value_type(value, types[i]) }
|
52
|
+
errors.concat values.each_with_index.flat_map { |value, i| errors_with_value_type(value, arguments.types[i]) }
|
51
53
|
end
|
52
54
|
end
|
53
55
|
end
|
@@ -78,13 +80,16 @@ module SetBuilder
|
|
78
80
|
|
79
81
|
|
80
82
|
|
81
|
-
def to_s
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
83
|
+
def to_s
|
84
|
+
arguments = self.class.parsed_operators[operator] || Arguments.new("")
|
85
|
+
operator.to_s.gsub(/_/, " ") + " " + arguments.to_s(values)
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
def self.parsed_operators
|
91
|
+
@parsed_operators ||= Hash[operators.map { |operator, arguments|
|
92
|
+
[operator, Arguments.new(arguments)] }]
|
88
93
|
end
|
89
94
|
|
90
95
|
|
@@ -96,11 +101,8 @@ module SetBuilder
|
|
96
101
|
|
97
102
|
|
98
103
|
def self.to_hash
|
99
|
-
|
100
|
-
|
101
|
-
hash[operator.to_s] = array.map {|type| type.to_s }
|
102
|
-
end
|
103
|
-
hash
|
104
|
+
Hash[parsed_operators.map { |operator, arguments|
|
105
|
+
[operator.to_s, arguments.as_json] }]
|
104
106
|
end
|
105
107
|
|
106
108
|
|
@@ -7,14 +7,14 @@ module SetBuilder
|
|
7
7
|
|
8
8
|
def self.operators
|
9
9
|
{
|
10
|
-
:ever =>
|
11
|
-
:before =>
|
12
|
-
:after =>
|
13
|
-
:on =>
|
14
|
-
:during_month =>
|
15
|
-
:during_year =>
|
16
|
-
:in_the_last =>
|
17
|
-
:between =>
|
10
|
+
:ever => "",
|
11
|
+
:before => "{date}",
|
12
|
+
:after => "{date}",
|
13
|
+
:on => "{date}",
|
14
|
+
:during_month => "{month}",
|
15
|
+
:during_year => "{year}",
|
16
|
+
:in_the_last => "{number} {period}",
|
17
|
+
:between => "{date} and {date}"
|
18
18
|
}
|
19
19
|
end
|
20
20
|
|
@@ -7,10 +7,10 @@ module SetBuilder
|
|
7
7
|
|
8
8
|
def self.operators
|
9
9
|
{
|
10
|
-
:is =>
|
11
|
-
:is_less_than =>
|
12
|
-
:is_greater_than =>
|
13
|
-
:is_between =>
|
10
|
+
:is => "{number}",
|
11
|
+
:is_less_than => "{number}",
|
12
|
+
:is_greater_than => "{number}",
|
13
|
+
:is_between => "{number} and {number}"
|
14
14
|
}
|
15
15
|
end
|
16
16
|
|
@@ -7,14 +7,14 @@ module SetBuilder
|
|
7
7
|
|
8
8
|
def self.operators
|
9
9
|
{
|
10
|
-
:contains =>
|
11
|
-
:does_not_contain =>
|
12
|
-
:begins_with =>
|
13
|
-
:does_not_begin_with =>
|
14
|
-
:ends_with =>
|
15
|
-
:does_not_end_with =>
|
16
|
-
:is =>
|
17
|
-
:is_not =>
|
10
|
+
:contains => "{string}",
|
11
|
+
:does_not_contain => "{string}",
|
12
|
+
:begins_with => "{string}",
|
13
|
+
:does_not_begin_with => "{string}",
|
14
|
+
:ends_with => "{string}",
|
15
|
+
:does_not_end_with => "{string}",
|
16
|
+
:is => "{string}",
|
17
|
+
:is_not => "{string}"
|
18
18
|
}
|
19
19
|
end
|
20
20
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module SetBuilder
|
2
|
+
module Parser
|
3
|
+
|
4
|
+
def parse(expression)
|
5
|
+
tokenizer = Regexp.union(LEXER.values)
|
6
|
+
expression.split(tokenizer).each_with_object([]) do |lexeme, output|
|
7
|
+
next if lexeme.empty?
|
8
|
+
token = token_for(lexeme)
|
9
|
+
output.push [token, value_for(token, lexeme)]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def token_for(lexeme)
|
14
|
+
LEXER.each { |token, pattern| return token if pattern.match(lexeme) }
|
15
|
+
:string
|
16
|
+
end
|
17
|
+
|
18
|
+
def value_for(token, lexeme)
|
19
|
+
case token
|
20
|
+
when :name, :modifier, :arg then lexeme[1...-1]
|
21
|
+
when :enum then lexeme[1...-1].split("|")
|
22
|
+
when :direct_object_type then lexeme[1..-1]
|
23
|
+
else lexeme
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
LEXER = {
|
28
|
+
name: /("[^"]+")/,
|
29
|
+
direct_object_type: /(:[\w\-\.]+)/,
|
30
|
+
enum: /(\[[^\]]+\])/,
|
31
|
+
modifier: /(<\w+>)/,
|
32
|
+
arg: /(\{[^\}]+\})/
|
33
|
+
}.freeze
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
data/lib/set_builder/trait.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
require "set_builder/constraint"
|
2
2
|
require "set_builder/modifier"
|
3
|
+
require "set_builder/parser"
|
3
4
|
|
4
5
|
|
5
6
|
module SetBuilder
|
6
7
|
class Trait
|
7
8
|
attr_reader :expression, :tokens, :name, :modifiers, :direct_object_type, :enums
|
8
9
|
|
10
|
+
include Parser
|
9
11
|
|
10
12
|
|
11
13
|
def initialize(expression, &block)
|
@@ -65,38 +67,5 @@ module SetBuilder
|
|
65
67
|
|
66
68
|
|
67
69
|
|
68
|
-
def parse(expression)
|
69
|
-
tokenizer = Regexp.union(LEXER.values)
|
70
|
-
expression.split(tokenizer).each_with_object([]) do |lexeme, output|
|
71
|
-
next if lexeme.empty?
|
72
|
-
token = token_for(lexeme)
|
73
|
-
output.push [token, value_for(token, lexeme)]
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def token_for(lexeme)
|
78
|
-
LEXER.each { |token, pattern| return token if pattern.match(lexeme) }
|
79
|
-
:string
|
80
|
-
end
|
81
|
-
|
82
|
-
def value_for(token, lexeme)
|
83
|
-
case token
|
84
|
-
when :name then lexeme[1...-1]
|
85
|
-
when :enum then lexeme[1...-1].split("|")
|
86
|
-
when :modifier then lexeme[1...-1]
|
87
|
-
when :direct_object_type then lexeme[1..-1]
|
88
|
-
else lexeme
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
LEXER = {
|
93
|
-
name: /("[^"]+")/,
|
94
|
-
direct_object_type: /(:[\w\-\.]+)/,
|
95
|
-
enum: /(\[[^\]]+\])/,
|
96
|
-
modifier: /(<\w+>)/
|
97
|
-
}.freeze
|
98
|
-
|
99
|
-
|
100
|
-
|
101
70
|
end
|
102
71
|
end
|
data/lib/set_builder/version.rb
CHANGED
@@ -32,10 +32,13 @@ describe 'SetBuilder'
|
|
32
32
|
|
33
33
|
SetBuilder.registerModifiers({
|
34
34
|
string: {
|
35
|
-
contains: ['string'],
|
36
|
-
begins_with: ['string'],
|
37
|
-
ends_with: ['string'],
|
38
|
-
is: ['string']
|
35
|
+
contains: [['arg', 'string']],
|
36
|
+
begins_with: [['arg', 'string']],
|
37
|
+
ends_with: [['arg', 'string']],
|
38
|
+
is: [['arg', 'string']]
|
39
|
+
},
|
40
|
+
date: {
|
41
|
+
between: [['arg', 'date'], ['string', ' and '], ['arg', 'date']]
|
39
42
|
}
|
40
43
|
});
|
41
44
|
|
@@ -60,6 +63,20 @@ describe 'SetBuilder'
|
|
60
63
|
|
61
64
|
|
62
65
|
|
66
|
+
describe '.registerValueMap'
|
67
|
+
it 'should accept an array of arrays as a valueMap'
|
68
|
+
SetBuilder.registerValueMap('name', [['1', 'John'], ['2', 'Susan']]);
|
69
|
+
expect(SetBuilder.getValueMap('name')).to(eql, [['1', 'John'], ['2', 'Susan']]);
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should accept and call a function as a valueMap'
|
73
|
+
var events = [['1', 'Band Rehearsal']];
|
74
|
+
SetBuilder.registerValueMap('event', function () { return events });
|
75
|
+
expect(SetBuilder.getValueMap('event')).to(eql, events);
|
76
|
+
events.push(['2', 'Basketball Practice']);
|
77
|
+
expect(SetBuilder.getValueMap('event')).to(eql, events);
|
78
|
+
end
|
79
|
+
end
|
63
80
|
|
64
81
|
describe '.getValueMap'
|
65
82
|
it 'should return an array of arrays'
|
@@ -80,7 +97,7 @@ describe 'SetBuilder'
|
|
80
97
|
|
81
98
|
describe '.getValueMaps'
|
82
99
|
it 'should return the names of the value maps registered'
|
83
|
-
expect(SetBuilder.getValueMaps()).to(eql, ['school']);
|
100
|
+
expect(SetBuilder.getValueMaps()).to(eql, ['school', 'name', 'event']);
|
84
101
|
end
|
85
102
|
end
|
86
103
|
|
@@ -139,7 +156,7 @@ describe 'SetBuilder'
|
|
139
156
|
|
140
157
|
describe '.length'
|
141
158
|
it 'should have parsed the data structure correctly'
|
142
|
-
|
159
|
+
expect(modifiers.length()).to(be, 2);
|
143
160
|
end
|
144
161
|
end
|
145
162
|
|
@@ -195,6 +212,14 @@ describe 'SetBuilder'
|
|
195
212
|
var expected_string = 'who are not awesome, who have not attended Concordia, who have not died, and whose name is Jerome'
|
196
213
|
expect(set.toString()).to(eql, expected_string);
|
197
214
|
end
|
215
|
+
|
216
|
+
it 'should generate the natural language description of a set with extra text in modifier arguments'
|
217
|
+
var set = new SetBuilder.Set([
|
218
|
+
{ trait: 'born', modifiers: [{ operator: 'between', values: ['Jan 1, 2016', 'Jan 2, 2016'] }]}
|
219
|
+
])
|
220
|
+
var expected_string = 'who were born between Jan 1, 2016 and Jan 2, 2016';
|
221
|
+
expect(set.toString()).to(eql, expected_string);
|
222
|
+
end
|
198
223
|
end
|
199
224
|
|
200
225
|
end
|
data/test/constraint_test.rb
CHANGED
@@ -3,6 +3,8 @@ require "test_helper"
|
|
3
3
|
class ConstraintTest < ActiveSupport::TestCase
|
4
4
|
include SetBuilder
|
5
5
|
|
6
|
+
attr_reader :trait, :constraint
|
7
|
+
|
6
8
|
|
7
9
|
test "constraints find correct modifiers" do
|
8
10
|
trait = $friend_traits[:name]
|
@@ -29,6 +31,40 @@ class ConstraintTest < ActiveSupport::TestCase
|
|
29
31
|
|
30
32
|
|
31
33
|
|
34
|
+
context "When a Constraint has fewer enum values than the Trait expects, it" do
|
35
|
+
setup do
|
36
|
+
@trait = Trait.new('who [is|is not] "awesome" at [basketball|golf|hockey]')
|
37
|
+
@constraint = trait.apply({enums: ["is not"]})
|
38
|
+
end
|
39
|
+
|
40
|
+
should "be valid" do
|
41
|
+
assert constraint.valid?, "The constraint was not valid: #{constraint.errors.join(";")}"
|
42
|
+
end
|
43
|
+
|
44
|
+
should "fill in the missing values with the first option the Trait defines" do
|
45
|
+
assert_equal "who is not awesome at basketball", constraint.to_s
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
context "When a Constraint is given an enum value that the Trait doesn't expect, it" do
|
52
|
+
setup do
|
53
|
+
@trait = Trait.new('who [is|is not] "awesome" at [basketball|golf|hockey]')
|
54
|
+
@constraint = trait.apply({enums: ["are not", "soccer"]})
|
55
|
+
end
|
56
|
+
|
57
|
+
should "be valid" do
|
58
|
+
assert constraint.valid?, "The constraint was not valid: #{constraint.errors.join(";")}"
|
59
|
+
end
|
60
|
+
|
61
|
+
should "replace the value with the first option the Trait defines" do
|
62
|
+
assert_equal "who is awesome at basketball", constraint.to_s
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
|
32
68
|
context "A constraint" do
|
33
69
|
should "be invalid if it is missing a direct object" do
|
34
70
|
trait = Trait.new('who "attended" :school')
|
@@ -36,18 +72,6 @@ class ConstraintTest < ActiveSupport::TestCase
|
|
36
72
|
assert_match /school is blank/, constraint.errors.join
|
37
73
|
end
|
38
74
|
|
39
|
-
should "be invalid if it is missing an enumeration" do
|
40
|
-
trait = Trait.new('who [is|is not] "awesome"')
|
41
|
-
constraint = trait.apply({})
|
42
|
-
assert_match /should have values for 1 enums/, constraint.errors.join
|
43
|
-
end
|
44
|
-
|
45
|
-
should "be invalid if it supplies an unexpected value for an enumeration" do
|
46
|
-
trait = Trait.new('who [is|is not] "awesome"')
|
47
|
-
constraint = trait.apply(enums: ["is totally"])
|
48
|
-
assert_match /should be 'is' or 'is not'/, constraint.errors.join
|
49
|
-
end
|
50
|
-
|
51
75
|
should "be invalid if it supplies an unexpected value for a modifier's operator" do
|
52
76
|
trait = Trait.new('whose "name" <string>')
|
53
77
|
constraint = trait.apply(modifiers: [{ operator: "starts_with", values: ["Jer"] }])
|
data/test/modifier_test.rb
CHANGED
@@ -55,14 +55,14 @@ class ModifierTest < ActiveSupport::TestCase
|
|
55
55
|
|
56
56
|
test "converting modifier to json" do
|
57
57
|
expected_results = {
|
58
|
-
"contains" => ["string"],
|
59
|
-
"does_not_contain" => ["string"],
|
60
|
-
"begins_with" => ["string"],
|
61
|
-
"does_not_begin_with" => ["string"],
|
62
|
-
"ends_with" => ["string"],
|
63
|
-
"does_not_end_with" => ["string"],
|
64
|
-
"is" => ["string"],
|
65
|
-
"is_not" => ["string"]
|
58
|
+
"contains" => [["arg", "string"]],
|
59
|
+
"does_not_contain" => [["arg", "string"]],
|
60
|
+
"begins_with" => [["arg", "string"]],
|
61
|
+
"does_not_begin_with" => [["arg", "string"]],
|
62
|
+
"ends_with" => [["arg", "string"]],
|
63
|
+
"does_not_end_with" => [["arg", "string"]],
|
64
|
+
"is" => [["arg", "string"]],
|
65
|
+
"is_not" => [["arg", "string"]]
|
66
66
|
}.to_json
|
67
67
|
assert_equal expected_results, SetBuilder::Modifier.for(:string).to_json
|
68
68
|
end
|
@@ -71,29 +71,29 @@ class ModifierTest < ActiveSupport::TestCase
|
|
71
71
|
expected_results = {
|
72
72
|
"date" => {
|
73
73
|
"ever" => [],
|
74
|
-
"
|
75
|
-
"
|
76
|
-
"on" => ["date"],
|
77
|
-
"
|
78
|
-
"
|
79
|
-
"
|
80
|
-
"between" => ["date", "date"]
|
74
|
+
"before" => [["arg", "date"]],
|
75
|
+
"after" => [["arg", "date"]],
|
76
|
+
"on" => [["arg", "date"]],
|
77
|
+
"during_month"=> [["arg", "month"]],
|
78
|
+
"during_year" => [["arg", "year"]],
|
79
|
+
"in_the_last" => [["arg", "number"], ["string", " "], ["arg", "period"]],
|
80
|
+
"between" => [["arg", "date"], ["string", " and "], ["arg", "date"]]
|
81
81
|
},
|
82
|
-
"number"=> {
|
83
|
-
"is"=>["number"],
|
84
|
-
"is_less_than"=>["number"],
|
85
|
-
"is_greater_than"=>["number"],
|
86
|
-
"is_between"=>["number", "number"]
|
82
|
+
"number" => {
|
83
|
+
"is"=>[["arg", "number"]],
|
84
|
+
"is_less_than"=>[["arg", "number"]],
|
85
|
+
"is_greater_than"=>[["arg", "number"]],
|
86
|
+
"is_between"=>[["arg", "number"], ["string", " and "], ["arg", "number"]]
|
87
87
|
},
|
88
88
|
"string" => {
|
89
|
-
"contains" => ["string"],
|
90
|
-
"does_not_contain" => ["string"],
|
91
|
-
"begins_with" => ["string"],
|
92
|
-
"does_not_begin_with" => ["string"],
|
93
|
-
"ends_with" => ["string"],
|
94
|
-
"does_not_end_with" => ["string"],
|
95
|
-
"is" => ["string"],
|
96
|
-
"is_not" => ["string"]
|
89
|
+
"contains" => [["arg", "string"]],
|
90
|
+
"does_not_contain" => [["arg", "string"]],
|
91
|
+
"begins_with" => [["arg", "string"]],
|
92
|
+
"does_not_begin_with" => [["arg", "string"]],
|
93
|
+
"ends_with" => [["arg", "string"]],
|
94
|
+
"does_not_end_with" => [["arg", "string"]],
|
95
|
+
"is" => [["arg", "string"]],
|
96
|
+
"is_not" => [["arg", "string"]]
|
97
97
|
}
|
98
98
|
}
|
99
99
|
assert_equal expected_results, $friend_traits.modifiers.to_hash
|
metadata
CHANGED
@@ -1,139 +1,158 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: set_builder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.beta4
|
5
|
+
prerelease: 6
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Bob Lail
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2016-
|
12
|
+
date: 2016-03-07 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: rails
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
16
18
|
requirements:
|
17
|
-
- -
|
19
|
+
- - ~>
|
18
20
|
- !ruby/object:Gem::Version
|
19
21
|
version: 4.2.0
|
20
22
|
type: :runtime
|
21
23
|
prerelease: false
|
22
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
23
26
|
requirements:
|
24
|
-
- -
|
27
|
+
- - ~>
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: 4.2.0
|
27
30
|
- !ruby/object:Gem::Dependency
|
28
31
|
name: arel
|
29
32
|
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
30
34
|
requirements:
|
31
|
-
- -
|
35
|
+
- - ! '>='
|
32
36
|
- !ruby/object:Gem::Version
|
33
37
|
version: '0'
|
34
38
|
type: :runtime
|
35
39
|
prerelease: false
|
36
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
37
42
|
requirements:
|
38
|
-
- -
|
43
|
+
- - ! '>='
|
39
44
|
- !ruby/object:Gem::Version
|
40
45
|
version: '0'
|
41
46
|
- !ruby/object:Gem::Dependency
|
42
47
|
name: bundler
|
43
48
|
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
44
50
|
requirements:
|
45
|
-
- -
|
51
|
+
- - ~>
|
46
52
|
- !ruby/object:Gem::Version
|
47
53
|
version: '1.3'
|
48
54
|
type: :development
|
49
55
|
prerelease: false
|
50
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
51
58
|
requirements:
|
52
|
-
- -
|
59
|
+
- - ~>
|
53
60
|
- !ruby/object:Gem::Version
|
54
61
|
version: '1.3'
|
55
62
|
- !ruby/object:Gem::Dependency
|
56
63
|
name: rake
|
57
64
|
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
58
66
|
requirements:
|
59
|
-
- -
|
67
|
+
- - ! '>='
|
60
68
|
- !ruby/object:Gem::Version
|
61
69
|
version: '0'
|
62
70
|
type: :development
|
63
71
|
prerelease: false
|
64
72
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
65
74
|
requirements:
|
66
|
-
- -
|
75
|
+
- - ! '>='
|
67
76
|
- !ruby/object:Gem::Version
|
68
77
|
version: '0'
|
69
78
|
- !ruby/object:Gem::Dependency
|
70
79
|
name: jspec
|
71
80
|
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
72
82
|
requirements:
|
73
|
-
- -
|
83
|
+
- - ! '>='
|
74
84
|
- !ruby/object:Gem::Version
|
75
85
|
version: '0'
|
76
86
|
type: :development
|
77
87
|
prerelease: false
|
78
88
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
79
90
|
requirements:
|
80
|
-
- -
|
91
|
+
- - ! '>='
|
81
92
|
- !ruby/object:Gem::Version
|
82
93
|
version: '0'
|
83
94
|
- !ruby/object:Gem::Dependency
|
84
95
|
name: pry
|
85
96
|
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
86
98
|
requirements:
|
87
|
-
- -
|
99
|
+
- - ! '>='
|
88
100
|
- !ruby/object:Gem::Version
|
89
101
|
version: '0'
|
90
102
|
type: :development
|
91
103
|
prerelease: false
|
92
104
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
93
106
|
requirements:
|
94
|
-
- -
|
107
|
+
- - ! '>='
|
95
108
|
- !ruby/object:Gem::Version
|
96
109
|
version: '0'
|
97
110
|
- !ruby/object:Gem::Dependency
|
98
111
|
name: shoulda-context
|
99
112
|
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
100
114
|
requirements:
|
101
|
-
- -
|
115
|
+
- - ! '>='
|
102
116
|
- !ruby/object:Gem::Version
|
103
117
|
version: '0'
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
107
122
|
requirements:
|
108
|
-
- -
|
123
|
+
- - ! '>='
|
109
124
|
- !ruby/object:Gem::Version
|
110
125
|
version: '0'
|
111
126
|
- !ruby/object:Gem::Dependency
|
112
127
|
name: minitest-reporters
|
113
128
|
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
114
130
|
requirements:
|
115
|
-
- -
|
131
|
+
- - ! '>='
|
116
132
|
- !ruby/object:Gem::Version
|
117
133
|
version: '0'
|
118
134
|
type: :development
|
119
135
|
prerelease: false
|
120
136
|
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
121
138
|
requirements:
|
122
|
-
- -
|
139
|
+
- - ! '>='
|
123
140
|
- !ruby/object:Gem::Version
|
124
141
|
version: '0'
|
125
142
|
- !ruby/object:Gem::Dependency
|
126
143
|
name: timecop
|
127
144
|
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
128
146
|
requirements:
|
129
|
-
- -
|
147
|
+
- - ! '>='
|
130
148
|
- !ruby/object:Gem::Version
|
131
149
|
version: '0'
|
132
150
|
type: :development
|
133
151
|
prerelease: false
|
134
152
|
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
135
154
|
requirements:
|
136
|
-
- -
|
155
|
+
- - ! '>='
|
137
156
|
- !ruby/object:Gem::Version
|
138
157
|
version: '0'
|
139
158
|
description: A gem for describing constraints on data sets
|
@@ -143,8 +162,8 @@ executables: []
|
|
143
162
|
extensions: []
|
144
163
|
extra_rdoc_files: []
|
145
164
|
files:
|
146
|
-
-
|
147
|
-
-
|
165
|
+
- .gitignore
|
166
|
+
- .travis.yml
|
148
167
|
- Gemfile
|
149
168
|
- MIT-LICENSE
|
150
169
|
- README.md
|
@@ -158,6 +177,7 @@ files:
|
|
158
177
|
- lib/set_builder/errors/trait_not_found.rb
|
159
178
|
- lib/set_builder/modifier.rb
|
160
179
|
- lib/set_builder/modifier/adverb.rb
|
180
|
+
- lib/set_builder/modifier/arguments.rb
|
161
181
|
- lib/set_builder/modifier/base.rb
|
162
182
|
- lib/set_builder/modifier/verb.rb
|
163
183
|
- lib/set_builder/modifier_collection.rb
|
@@ -165,6 +185,7 @@ files:
|
|
165
185
|
- lib/set_builder/modifiers/date_preposition.rb
|
166
186
|
- lib/set_builder/modifiers/number_preposition.rb
|
167
187
|
- lib/set_builder/modifiers/string_preposition.rb
|
188
|
+
- lib/set_builder/parser.rb
|
168
189
|
- lib/set_builder/set.rb
|
169
190
|
- lib/set_builder/trait.rb
|
170
191
|
- lib/set_builder/trait_builder.rb
|
@@ -209,26 +230,30 @@ files:
|
|
209
230
|
homepage: ''
|
210
231
|
licenses:
|
211
232
|
- MIT
|
212
|
-
metadata: {}
|
213
233
|
post_install_message:
|
214
234
|
rdoc_options: []
|
215
235
|
require_paths:
|
216
236
|
- lib
|
217
237
|
required_ruby_version: !ruby/object:Gem::Requirement
|
238
|
+
none: false
|
218
239
|
requirements:
|
219
|
-
- -
|
240
|
+
- - ! '>='
|
220
241
|
- !ruby/object:Gem::Version
|
221
242
|
version: '0'
|
243
|
+
segments:
|
244
|
+
- 0
|
245
|
+
hash: -2909033226206724461
|
222
246
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
247
|
+
none: false
|
223
248
|
requirements:
|
224
|
-
- -
|
249
|
+
- - ! '>'
|
225
250
|
- !ruby/object:Gem::Version
|
226
251
|
version: 1.3.1
|
227
252
|
requirements: []
|
228
253
|
rubyforge_project:
|
229
|
-
rubygems_version:
|
254
|
+
rubygems_version: 1.8.23.2
|
230
255
|
signing_key:
|
231
|
-
specification_version:
|
256
|
+
specification_version: 3
|
232
257
|
summary: Define traits on a model, create sets that constrain those traits, and generate
|
233
258
|
both natural-language descriptions of the sets and queries to select them
|
234
259
|
test_files:
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz: acd34d467c6aca8cc3c42db795261de035c72c58
|
4
|
-
data.tar.gz: 2c08cc3a703c5cc84230cbaa0e047004d4e7f430
|
5
|
-
SHA512:
|
6
|
-
metadata.gz: d79aec9ff59f398bc844de87cbc9a7946fb43166017d1231c36fc8a1ff267a296a98e88e524d3b01b2c726bd91ed75d4e63833246e32cc6fa25114e038809cb1
|
7
|
-
data.tar.gz: d4ba5f0e2dfff5ad5245abd758adcac891c93fe2e0bba30c830e52b7dd63e7749962ed6843dc4f3c4b33b1e7b3a3b33dcb58ceef97312a417cce6abbf8be8962
|