smartdown 0.9.0 → 0.10.0
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.
- data/README.md +15 -0
- data/lib/smartdown/api/date_question.rb +33 -0
- data/lib/smartdown/engine/interpolator.rb +4 -1
- data/lib/smartdown/model/element/question/date.rb +1 -1
- data/lib/smartdown/parser/flow_interpreter.rb +5 -1
- data/lib/smartdown/parser/node_interpreter.rb +3 -2
- data/lib/smartdown/parser/node_transform.rb +4 -1
- data/lib/smartdown/parser/predicates.rb +1 -1
- data/lib/smartdown/version.rb +1 -1
- data/spec/api/date_question_spec.rb +71 -0
- data/spec/parser/element/date_question_spec.rb +33 -1
- data/spec/parser/predicates_spec.rb +5 -5
- data/spec/spec_helper.rb +1 -0
- metadata +24 -11
data/README.md
CHANGED
|
@@ -127,6 +127,21 @@ country slugs/names.
|
|
|
127
127
|
[date: baby_due_date]
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
+
To control the range of years selected you can supply 2 optional arguments to date questions: `from` and `to`.
|
|
131
|
+
These can take the form of absolute values, eg.
|
|
132
|
+
|
|
133
|
+
```markdown
|
|
134
|
+
[date: baby_due_date, from: 2010, to: 2015]
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Or relative values (from the current year), eg.
|
|
138
|
+
|
|
139
|
+
```markdown
|
|
140
|
+
[date: baby_due_date, from: -4, to: 1]
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The default values for `from` and `to` are relative years: `-1` and `3` respectively.
|
|
144
|
+
|
|
130
145
|
### Text
|
|
131
146
|
|
|
132
147
|
```markdown
|
|
@@ -3,6 +3,39 @@ require 'smartdown/api/question'
|
|
|
3
3
|
module Smartdown
|
|
4
4
|
module Api
|
|
5
5
|
class DateQuestion < Question
|
|
6
|
+
extend Forwardable
|
|
7
|
+
DEFAULT_START_YEAR = Time.now.year - 1
|
|
8
|
+
DEFAULT_END_YEAR = Time.now.year + 3
|
|
9
|
+
|
|
10
|
+
def start_year
|
|
11
|
+
parse_date(from) || DEFAULT_START_YEAR
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def end_year
|
|
15
|
+
parse_date(to) || DEFAULT_END_YEAR
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
delegate [:to, :from] => :question_element
|
|
21
|
+
|
|
22
|
+
def question_element
|
|
23
|
+
@question_element ||= elements.find{|element| element.is_a? Smartdown::Model::Element::Question::Date}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def parse_date(date_string)
|
|
27
|
+
return nil unless date_string
|
|
28
|
+
year = date_string.to_i
|
|
29
|
+
if is_fixed_year?(year)
|
|
30
|
+
year
|
|
31
|
+
else
|
|
32
|
+
Time.now.year + year
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def is_fixed_year?(int)
|
|
37
|
+
int.abs >= 1000
|
|
38
|
+
end
|
|
6
39
|
end
|
|
7
40
|
end
|
|
8
41
|
end
|
|
@@ -41,7 +41,10 @@ module Smartdown
|
|
|
41
41
|
def interpolate(text, state)
|
|
42
42
|
text.to_s.gsub(/%{([^}]+)}/) do |_|
|
|
43
43
|
term = resolve_term($1, state)
|
|
44
|
-
term.
|
|
44
|
+
if term.is_a?(Smartdown::Model::Answer::Base)
|
|
45
|
+
term = term.humanize
|
|
46
|
+
end
|
|
47
|
+
term
|
|
45
48
|
end
|
|
46
49
|
end
|
|
47
50
|
|
|
@@ -13,7 +13,11 @@ module Smartdown
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def to_s(full = true)
|
|
16
|
-
|
|
16
|
+
position = parse_error.cause.pos
|
|
17
|
+
line, column = parse_error.cause.source.line_and_column(position)
|
|
18
|
+
|
|
19
|
+
"Parse error in file:'#{filename}' line:'#{line}' column:'#{column}'" +
|
|
20
|
+
"\n\n" + parse_error.cause.ascii_tree
|
|
17
21
|
end
|
|
18
22
|
end
|
|
19
23
|
|
|
@@ -7,7 +7,7 @@ require 'smartdown/parser/node_transform'
|
|
|
7
7
|
module Smartdown
|
|
8
8
|
module Parser
|
|
9
9
|
class NodeInterpreter
|
|
10
|
-
attr_reader :name, :source
|
|
10
|
+
attr_reader :name, :source, :reporter
|
|
11
11
|
|
|
12
12
|
def initialize(name, source, options = {})
|
|
13
13
|
@name = name
|
|
@@ -15,10 +15,11 @@ module Smartdown
|
|
|
15
15
|
data_module = options.fetch(:data_module, {})
|
|
16
16
|
@parser = options.fetch(:parser, Smartdown::Parser::NodeParser.new)
|
|
17
17
|
@transform = options.fetch(:transform, Smartdown::Parser::NodeTransform.new(data_module))
|
|
18
|
+
@reporter = options.fetch(:reporter, Parslet::ErrorReporter::Deepest.new)
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
def interpret
|
|
21
|
-
transform.apply(parser.parse(source),
|
|
22
|
+
transform.apply(parser.parse(source, reporter: reporter),
|
|
22
23
|
node_name: name
|
|
23
24
|
)
|
|
24
25
|
end
|
|
@@ -102,9 +102,12 @@ module Smartdown
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
rule(:date => {identifier: simple(:identifier), :option_pairs => subtree(:option_pairs)}) {
|
|
105
|
+
transformed_option_pairs = Smartdown::Parser::OptionPairs.transform(option_pairs)
|
|
105
106
|
Smartdown::Model::Element::Question::Date.new(
|
|
106
107
|
identifier.to_s,
|
|
107
|
-
|
|
108
|
+
transformed_option_pairs.fetch('from', nil),
|
|
109
|
+
transformed_option_pairs.fetch('to', nil),
|
|
110
|
+
transformed_option_pairs.fetch('alias', nil),
|
|
108
111
|
)
|
|
109
112
|
}
|
|
110
113
|
|
|
@@ -45,6 +45,7 @@ module Smartdown
|
|
|
45
45
|
equality_predicate.as(:equality_predicate) |
|
|
46
46
|
set_membership_predicate.as(:set_membership_predicate) |
|
|
47
47
|
comparison_predicate.as(:comparison_predicate) |
|
|
48
|
+
function_predicate.as(:function_predicate) |
|
|
48
49
|
otherwise_predicate |
|
|
49
50
|
named_predicate
|
|
50
51
|
}
|
|
@@ -68,7 +69,6 @@ module Smartdown
|
|
|
68
69
|
|
|
69
70
|
rule (:predicates) {
|
|
70
71
|
combined_predicate.as(:combined_predicate) |
|
|
71
|
-
function_predicate.as(:function_predicate) |
|
|
72
72
|
predicate
|
|
73
73
|
}
|
|
74
74
|
|
data/lib/smartdown/version.rb
CHANGED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require 'smartdown/api/date_question'
|
|
2
|
+
require 'smartdown/model/element/question/date'
|
|
3
|
+
|
|
4
|
+
describe Smartdown::Api::DateQuestion do
|
|
5
|
+
before do
|
|
6
|
+
Timecop.freeze(Time.local(2014))
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
after do
|
|
10
|
+
Timecop.return
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
subject(:date_question) { Smartdown::Api::DateQuestion.new(elements) }
|
|
14
|
+
let(:elements) { [ date_question_element ] }
|
|
15
|
+
let(:date_question_element) {
|
|
16
|
+
Smartdown::Model::Element::Question::Date.new(name, *args)
|
|
17
|
+
}
|
|
18
|
+
let(:aliaz) { nil }
|
|
19
|
+
let(:args) {[start_year, end_year, aliaz]}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
context "no to/from provided" do
|
|
23
|
+
let(:name) { 'year_of_emancipation' }
|
|
24
|
+
let(:start_year) { nil }
|
|
25
|
+
let(:end_year) { nil }
|
|
26
|
+
|
|
27
|
+
describe "#start_year" do
|
|
28
|
+
it 'returns good default' do
|
|
29
|
+
expect(date_question.start_year).to eq(Time.now.year - 1)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "#end_year" do
|
|
34
|
+
it 'returns good default' do
|
|
35
|
+
expect(date_question.end_year).to eq(Time.now.year + 3)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
context "with to/from provided" do
|
|
41
|
+
context "Fixed years" do
|
|
42
|
+
let(:name) { 'year_of_incarceration_for_possession_of_alcohol' }
|
|
43
|
+
let(:start_year) { '1920' }
|
|
44
|
+
let(:end_year) { '1933' }
|
|
45
|
+
|
|
46
|
+
describe "start_year" do
|
|
47
|
+
specify { expect(date_question.start_year).to eq(start_year.to_i) }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe "end_year" do
|
|
51
|
+
specify { expect(date_question.end_year).to eq(end_year.to_i) }
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context "Relative years" do
|
|
56
|
+
let(:name) { 'year_of_incarceration_for_practicing_witchcraft' }
|
|
57
|
+
let(:start_year) { '-279' }
|
|
58
|
+
let(:end_year) { '-63' }
|
|
59
|
+
|
|
60
|
+
describe "start_year" do
|
|
61
|
+
specify { expect(date_question.start_year).to eq(1735) }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe "end_year" do
|
|
65
|
+
specify { expect(date_question.end_year).to eq(1951) }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
@@ -27,6 +27,38 @@ describe Smartdown::Parser::Element::DateQuestion do
|
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
context "with question tag and a date range with years" do
|
|
31
|
+
let(:source) { "[date: date_of_birth, from: 1980, to: -2]" }
|
|
32
|
+
|
|
33
|
+
it "parses" do
|
|
34
|
+
should parse(source).as(
|
|
35
|
+
date: {
|
|
36
|
+
identifier: "date_of_birth",
|
|
37
|
+
option_pairs: [
|
|
38
|
+
{
|
|
39
|
+
key: 'from',
|
|
40
|
+
value: '1980',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
key: 'to',
|
|
44
|
+
value: '-2',
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
describe "transformed" do
|
|
53
|
+
let(:node_name) { "my_node" }
|
|
54
|
+
subject(:transformed) {
|
|
55
|
+
Smartdown::Parser::NodeInterpreter.new(node_name, source, parser: parser).interpret
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
it { should eq(Smartdown::Model::Element::Question::Date.new("date_of_birth", '1980', '-2')) }
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
30
62
|
context "with question tag and an alias" do
|
|
31
63
|
let(:source) { "[date: date_of_birth, alias: date_for_adoption_or_birth]" }
|
|
32
64
|
|
|
@@ -50,7 +82,7 @@ describe Smartdown::Parser::Element::DateQuestion do
|
|
|
50
82
|
Smartdown::Parser::NodeInterpreter.new(node_name, source, parser: parser).interpret
|
|
51
83
|
}
|
|
52
84
|
|
|
53
|
-
it { should eq(Smartdown::Model::Element::Question::Date.new("date_of_birth", "date_for_adoption_or_birth")) }
|
|
85
|
+
it { should eq(Smartdown::Model::Element::Question::Date.new("date_of_birth", nil, nil, "date_for_adoption_or_birth")) }
|
|
54
86
|
end
|
|
55
87
|
end
|
|
56
88
|
end
|
|
@@ -82,9 +82,9 @@ describe Smartdown::Parser::Predicates do
|
|
|
82
82
|
describe "predicate AND predicate" do
|
|
83
83
|
subject(:parser) { described_class.new }
|
|
84
84
|
|
|
85
|
-
it { should parse("my_pred
|
|
85
|
+
it { should parse("my_pred() AND my_other_pred?").as(
|
|
86
86
|
{ combined_predicate: {
|
|
87
|
-
first_predicate: {
|
|
87
|
+
first_predicate: { function_predicate: { name: "my_pred" } },
|
|
88
88
|
and_predicates:
|
|
89
89
|
[
|
|
90
90
|
{named_predicate: "my_other_pred?"},
|
|
@@ -107,16 +107,16 @@ describe Smartdown::Parser::Predicates do
|
|
|
107
107
|
|
|
108
108
|
describe "transformed" do
|
|
109
109
|
let(:node_name) { "my_node" }
|
|
110
|
-
let(:source) { "my_pred
|
|
110
|
+
let(:source) { "my_pred() AND my_other_pred?" }
|
|
111
111
|
subject(:transformed) {
|
|
112
112
|
Smartdown::Parser::NodeInterpreter.new(node_name, source, parser: parser).interpret
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
it { should eq(Smartdown::Model::Predicate::Combined.new(
|
|
116
116
|
[
|
|
117
|
-
Smartdown::Model::Predicate::
|
|
117
|
+
Smartdown::Model::Predicate::Function.new("my_pred", []),
|
|
118
118
|
Smartdown::Model::Predicate::Named.new("my_other_pred?")
|
|
119
|
-
|
|
119
|
+
]
|
|
120
120
|
)) }
|
|
121
121
|
end
|
|
122
122
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: smartdown
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.10.0
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -13,7 +13,7 @@ date: 2014-07-09 00:00:00.000000000 Z
|
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: parslet
|
|
16
|
-
requirement: &
|
|
16
|
+
requirement: &18204100 !ruby/object:Gem::Requirement
|
|
17
17
|
none: false
|
|
18
18
|
requirements:
|
|
19
19
|
- - ~>
|
|
@@ -21,10 +21,10 @@ dependencies:
|
|
|
21
21
|
version: 1.6.1
|
|
22
22
|
type: :runtime
|
|
23
23
|
prerelease: false
|
|
24
|
-
version_requirements: *
|
|
24
|
+
version_requirements: *18204100
|
|
25
25
|
- !ruby/object:Gem::Dependency
|
|
26
26
|
name: rspec
|
|
27
|
-
requirement: &
|
|
27
|
+
requirement: &18232520 !ruby/object:Gem::Requirement
|
|
28
28
|
none: false
|
|
29
29
|
requirements:
|
|
30
30
|
- - ~>
|
|
@@ -32,10 +32,10 @@ dependencies:
|
|
|
32
32
|
version: 3.0.0
|
|
33
33
|
type: :development
|
|
34
34
|
prerelease: false
|
|
35
|
-
version_requirements: *
|
|
35
|
+
version_requirements: *18232520
|
|
36
36
|
- !ruby/object:Gem::Dependency
|
|
37
37
|
name: rake
|
|
38
|
-
requirement: &
|
|
38
|
+
requirement: &18231800 !ruby/object:Gem::Requirement
|
|
39
39
|
none: false
|
|
40
40
|
requirements:
|
|
41
41
|
- - ! '>='
|
|
@@ -43,10 +43,10 @@ dependencies:
|
|
|
43
43
|
version: '0'
|
|
44
44
|
type: :development
|
|
45
45
|
prerelease: false
|
|
46
|
-
version_requirements: *
|
|
46
|
+
version_requirements: *18231800
|
|
47
47
|
- !ruby/object:Gem::Dependency
|
|
48
48
|
name: gem_publisher
|
|
49
|
-
requirement: &
|
|
49
|
+
requirement: &18230980 !ruby/object:Gem::Requirement
|
|
50
50
|
none: false
|
|
51
51
|
requirements:
|
|
52
52
|
- - ! '>='
|
|
@@ -54,7 +54,18 @@ dependencies:
|
|
|
54
54
|
version: '0'
|
|
55
55
|
type: :development
|
|
56
56
|
prerelease: false
|
|
57
|
-
version_requirements: *
|
|
57
|
+
version_requirements: *18230980
|
|
58
|
+
- !ruby/object:Gem::Dependency
|
|
59
|
+
name: timecop
|
|
60
|
+
requirement: &18230000 !ruby/object:Gem::Requirement
|
|
61
|
+
none: false
|
|
62
|
+
requirements:
|
|
63
|
+
- - ! '>='
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: '0'
|
|
66
|
+
type: :development
|
|
67
|
+
prerelease: false
|
|
68
|
+
version_requirements: *18230000
|
|
58
69
|
description:
|
|
59
70
|
email: david.heath@digital.cabinet-office.gov.uk
|
|
60
71
|
executables:
|
|
@@ -176,6 +187,7 @@ files:
|
|
|
176
187
|
- spec/support/flow_input_interface.rb
|
|
177
188
|
- spec/support/model_builder.rb
|
|
178
189
|
- spec/api/state_spec.rb
|
|
190
|
+
- spec/api/date_question_spec.rb
|
|
179
191
|
- spec/api/previous_question_spec.rb
|
|
180
192
|
- spec/spec_helper.rb
|
|
181
193
|
- spec/engine/state_spec.rb
|
|
@@ -252,7 +264,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
252
264
|
version: '0'
|
|
253
265
|
segments:
|
|
254
266
|
- 0
|
|
255
|
-
hash:
|
|
267
|
+
hash: 508907290184423365
|
|
256
268
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
257
269
|
none: false
|
|
258
270
|
requirements:
|
|
@@ -261,7 +273,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
261
273
|
version: '0'
|
|
262
274
|
segments:
|
|
263
275
|
- 0
|
|
264
|
-
hash:
|
|
276
|
+
hash: 508907290184423365
|
|
265
277
|
requirements: []
|
|
266
278
|
rubyforge_project:
|
|
267
279
|
rubygems_version: 1.8.11
|
|
@@ -295,6 +307,7 @@ test_files:
|
|
|
295
307
|
- spec/support/flow_input_interface.rb
|
|
296
308
|
- spec/support/model_builder.rb
|
|
297
309
|
- spec/api/state_spec.rb
|
|
310
|
+
- spec/api/date_question_spec.rb
|
|
298
311
|
- spec/api/previous_question_spec.rb
|
|
299
312
|
- spec/spec_helper.rb
|
|
300
313
|
- spec/engine/state_spec.rb
|