lunokhod 0.0.1.pre

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.
@@ -0,0 +1,41 @@
1
+ require 'lunokhod/rule_parser'
2
+ require 'set'
3
+
4
+ module Lunokhod
5
+ # Rules are chains of condition tags joined by ANDs and ORs.
6
+ # Parentheses may be used to modify precedence.
7
+ #
8
+ # Examples:
9
+ #
10
+ # A
11
+ # A or B
12
+ # A and (B or C)
13
+ # A and (B or (C and D))
14
+ #
15
+ # Surveyor actually uses eval (!) to evaluate dependencies. This means that
16
+ # Surveyor's dependency language inherits its precedence rules from Ruby.
17
+ module RuleParsing
18
+ attr_reader :parsed_rule
19
+
20
+ def parse_rule
21
+ parser = RuleParser.new(rule)
22
+ parser.parse
23
+ @parsed_rule = parser.ast
24
+ end
25
+
26
+ def referenced_conditions
27
+ Set.new.tap do |cs|
28
+ visit_rule { |n| cs << n.name if n.respond_to?(:name) }
29
+ end
30
+ end
31
+
32
+ def visit_rule(rule = parsed_rule, &block)
33
+ yield rule
34
+
35
+ if rule.respond_to?(:conj)
36
+ visit_rule(rule.left, &block)
37
+ visit_rule(rule.right, &block)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,155 @@
1
+ require 'lunokhod/ast'
2
+ require 'lunokhod/visitation'
3
+
4
+ module Lunokhod
5
+ class Verifier
6
+ include Ast
7
+ include Visitation
8
+
9
+ attr_reader :atag_count
10
+ attr_reader :atag_expectations
11
+ attr_reader :by_qref
12
+ attr_reader :ctag_count
13
+ attr_reader :qtag_count
14
+ attr_reader :qtag_expectations
15
+ attr_reader :survey
16
+
17
+ def initialize(survey)
18
+ @atag_count = Hash.new(0)
19
+ @atag_expectations = Hash.new(0)
20
+ @by_qref = {}
21
+ @ctag_count = Hash.new(0)
22
+ @qtag_count = Hash.new(0)
23
+ @qtag_expectations = Hash.new(0)
24
+ @survey = survey
25
+ end
26
+
27
+ def run(&block)
28
+ visit(survey, true) do |n, level, prev, boundary|
29
+ case n
30
+ when Condition; inspect_condition(n)
31
+ when Dependency, Validation; inspect_conditional(n)
32
+ when Question; inspect_question(n)
33
+ end
34
+ end
35
+
36
+ run_checks(&block)
37
+ end
38
+
39
+ # When we see a question:
40
+ #
41
+ # 1. If the question has a non-empty tag, index the question by its tag.
42
+ # 2. Register references to it and all of its answers.
43
+ def inspect_question(q)
44
+ index_question(q) unless q.tag.empty?
45
+ ref_question(q)
46
+ q.answers.each { |a| ref_answer(q, a) }
47
+ end
48
+
49
+ # There are three references in conditions that we have to worry about:
50
+ #
51
+ # - the question ref, if one exists
52
+ # - the answer ref, if one exists
53
+ # - the condition tag
54
+ #
55
+ # Seeing a condition registers a reference to the condition and
56
+ # expectations for the qref and aref if those refs exist.
57
+ def inspect_condition(c)
58
+ pc = c.parsed_condition
59
+
60
+ ctag_count[[c.parent, c.tag]] += 1
61
+
62
+ pending_question(pc.qtag, c) if pc.qtag
63
+ pending_answer(pc.qtag, pc.atag, c) if pc.qtag && pc.atag
64
+ end
65
+
66
+ # When we see a dependency or validation, register references to all of its
67
+ # conditions.
68
+ def inspect_conditional(c)
69
+ c.referenced_conditions.each do |tag|
70
+ key = [c, tag]
71
+
72
+ unless ctag_count.has_key?(key)
73
+ ctag_count[key] = 0
74
+ end
75
+ end
76
+ end
77
+
78
+ # Find all unsatisfied expectations.
79
+ def run_checks
80
+ bad_refs(qtag_count) do |qt|
81
+ yield Error.new(survey, Question, :bad_ref, qt, qtag_expectations[qt])
82
+ end
83
+
84
+ bad_refs(atag_count) do |qt, at|
85
+ yield Error.new(survey, Answer, :bad_ref, at, atag_expectations[[qt, at]])
86
+ end
87
+
88
+ bad_refs(ctag_count) do |c, tag|
89
+ yield Error.new(survey, Condition, :bad_ref, tag, c)
90
+ end
91
+
92
+ by_qref.select { |k, v| v.length > 1 }.each do |k, vs|
93
+ yield Error.new(survey, Question, :duplicate_qref, k, vs)
94
+ end
95
+ end
96
+
97
+ def bad_refs(refs)
98
+ refs.each { |k, c| yield k if c < 1 }
99
+ end
100
+
101
+ def index_question(q)
102
+ key = q.tag
103
+
104
+ by_qref[key] = [] unless by_qref.has_key?(key)
105
+ by_qref[key] << q
106
+ end
107
+
108
+ def ref_question(q)
109
+ qtag_count[q.tag.to_s] += 1
110
+ end
111
+
112
+ def ref_answer(q, a)
113
+ atag_count[[q.tag.to_s, a.tag.to_s]] += 1
114
+ end
115
+
116
+ def pending_question(qtag, from)
117
+ qtag_expectations[qtag] = from
118
+
119
+ unless qtag_count.has_key?(qtag)
120
+ qtag_count[qtag] = 0
121
+ end
122
+ end
123
+
124
+ def pending_answer(qtag, atag, from)
125
+ key = [qtag, atag]
126
+ atag_expectations[key] = from
127
+
128
+ unless atag_count.has_key?(key)
129
+ atag_count[key] = 0
130
+ end
131
+ end
132
+
133
+ class Error < Struct.new(:survey, :node_type, :error_type, :key, :at_fault)
134
+ def bad_question_tag?
135
+ bad_tag? && node_type == Ast::Question
136
+ end
137
+
138
+ def bad_answer_tag?
139
+ bad_tag? && node_type == Ast::Answer
140
+ end
141
+
142
+ def bad_condition?
143
+ bad_tag? && node_type == Ast::Condition
144
+ end
145
+
146
+ def duplicate_question?
147
+ error_type == :duplicate_qref
148
+ end
149
+
150
+ def bad_tag?
151
+ error_type == :bad_ref
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,3 @@
1
+ module Lunokhod
2
+ VERSION = '0.0.1.pre'
3
+ end
@@ -0,0 +1,12 @@
1
+ module Lunokhod
2
+ module Visitation
3
+ def visit(root, only_enter = false, level = 0, prev = nil, &block)
4
+ yield root, level, prev, :enter
5
+ root.children.each { |c| visit(c, only_enter, level + 1, root, &block) }
6
+
7
+ unless only_enter
8
+ yield root, level, prev, :exit
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'lunokhod/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "lunokhod"
8
+ spec.version = Lunokhod::VERSION
9
+ spec.authors = ["David Yip"]
10
+ spec.email = ["yipdw@northwestern.edu"]
11
+ spec.description = %q{Parsing and compilation tools for Surveyor surveys}
12
+ spec.summary = %q{Parsing and compilation tools for Surveyor surveys}
13
+ spec.homepage = "https://github.com/NUBIC/lunokhod"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'case'
22
+ spec.add_dependency 'uuidtools'
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.2"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency 'kpeg'
27
+ spec.add_development_dependency 'rspec'
28
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ module Lunokhod
4
+ describe ErrorReport do
5
+ let(:ep) { ErrorReport.new(surveys) }
6
+ let(:surveys) { p = Parser.new(data); p.parse; p.surveys }
7
+
8
+ describe '#run' do
9
+ let(:data) do
10
+ %q{survey "foo" do
11
+ section "bar" do
12
+ q_1 "a question"
13
+ a_1 "an answer"
14
+ dependency :rule => "A or B"
15
+ condition_A :q_oops, '==', :a_1
16
+ q_1 "duplicate"
17
+ a_1 "yep"
18
+ end
19
+ end
20
+
21
+ survey "bar" do
22
+ section "baz" do
23
+ q_1 "a question"
24
+ a_1 "an answer"
25
+ dependency :rule => "A"
26
+ condition_A :q_1, '==', :a_oops
27
+ end
28
+ end}
29
+ end
30
+
31
+ before do
32
+ ep.run
33
+ end
34
+
35
+ def errors_for(sname)
36
+ ep.errors.select { |e| e.survey.name == sname }
37
+ end
38
+
39
+ describe 'for each survey' do
40
+ it 'finds unknown question references' do
41
+ errors_for('foo').select(&:bad_question_tag?).length.should == 1
42
+ errors_for('bar').select(&:bad_question_tag?).length.should == 0
43
+ end
44
+
45
+ it 'finds unknown answer references' do
46
+ errors_for('foo').select(&:bad_answer_tag?).length.should == 1
47
+ errors_for('bar').select(&:bad_answer_tag?).length.should == 1
48
+ end
49
+
50
+ it 'finds unknown condition references' do
51
+ errors_for('foo').select(&:bad_condition?).length.should == 1
52
+ errors_for('bar').select(&:bad_condition?).length.should == 0
53
+ end
54
+
55
+ it 'finds duplicate question references' do
56
+ errors_for('foo').select(&:duplicate_question?).length.should == 1
57
+ errors_for('bar').select(&:duplicate_question?).length.should == 0
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+
3
+ module Lunokhod
4
+ describe Parser do
5
+ let(:parser) { Parser.new(data, 'fake') }
6
+ let(:ast) { parser.surveys.first }
7
+
8
+ describe 'for repeaters' do
9
+ let(:data) do
10
+ %q{
11
+ survey "fake" do
12
+ section "one" do
13
+ q_a "Eh?"
14
+ a_y "Yes"
15
+
16
+ repeater "I'm going to ask you a bunch of questions" do
17
+ dependency :rule => "A"
18
+ condition_A :q_a, "==", :a_y
19
+
20
+ q "Who is your daddy, and what does he do?"
21
+ a :string
22
+ end
23
+ end
24
+ end
25
+ }
26
+ end
27
+
28
+ before do
29
+ parser.parse
30
+ end
31
+
32
+ let(:repeater) { ast.sections[0].questions[1] }
33
+
34
+ it 'associates repeater dependencies with the repeater' do
35
+ repeater.dependencies.length.should == 1
36
+ end
37
+ end
38
+
39
+ describe 'for answers' do
40
+ let(:data) do
41
+ %q{
42
+ survey "fake" do
43
+ section "one" do
44
+ q_a "A question"
45
+ a "An answer", :string
46
+ a "An answer with options", :help_text => "Yep"
47
+ a "An answer with everything", :string, :help_text => "Yep"
48
+ a :string
49
+ a :other, :string
50
+ end
51
+ end
52
+ }
53
+ end
54
+
55
+ before do
56
+ parser.parse
57
+ end
58
+
59
+ let(:answers) { ast.sections[0].questions[0].answers }
60
+
61
+ it 'parses answer response class' do
62
+ answers[0].type.should == :string
63
+ answers[0].options.should be_empty
64
+ end
65
+
66
+ it 'parses options on answers' do
67
+ answers[1].options.should == { :help_text => 'Yep' }
68
+ end
69
+
70
+ it 'parses answers with options and response class' do
71
+ answers[2].type.should == :string
72
+ answers[2].options.should == { :help_text => 'Yep' }
73
+ end
74
+
75
+ it 'parses answers with a response class but no text' do
76
+ answers[3].type.should == :string
77
+ answers[3].options.should be_empty
78
+ end
79
+
80
+ it 'parses the "other" answer type with a response class' do
81
+ answers[4].should be_other
82
+ answers[4].type.should == :string
83
+ answers[4].options.should be_empty
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,6 @@
1
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
2
+
3
+ require 'lunokhod'
4
+
5
+ RSpec.configure do |c|
6
+ end
metadata ADDED
@@ -0,0 +1,181 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lunokhod
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.pre
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - David Yip
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: case
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: uuidtools
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1.2'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.2'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: kpeg
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: rspec
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: Parsing and compilation tools for Surveyor surveys
111
+ email:
112
+ - yipdw@northwestern.edu
113
+ executables:
114
+ - lunokhod-driver
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - .gitignore
119
+ - .gitmodules
120
+ - .travis.yml
121
+ - CHANGELOG
122
+ - Gemfile
123
+ - LICENSE
124
+ - README
125
+ - Rakefile
126
+ - TODO
127
+ - bin/lunokhod-driver
128
+ - kitchen_sink_survey.rb
129
+ - lib/lunokhod.rb
130
+ - lib/lunokhod/ast.rb
131
+ - lib/lunokhod/backends/debug.rb
132
+ - lib/lunokhod/backends/webpage.rb
133
+ - lib/lunokhod/backends/webpage/evaluator.js
134
+ - lib/lunokhod/backends/webpage/jquery.min.js
135
+ - lib/lunokhod/backends/webpage/page.html.erb
136
+ - lib/lunokhod/compiler.rb
137
+ - lib/lunokhod/condition_parsing.rb
138
+ - lib/lunokhod/error_report.rb
139
+ - lib/lunokhod/parser.rb
140
+ - lib/lunokhod/rule_parser.kpeg
141
+ - lib/lunokhod/rule_parser.rb
142
+ - lib/lunokhod/rule_parsing.rb
143
+ - lib/lunokhod/verifier.rb
144
+ - lib/lunokhod/version.rb
145
+ - lib/lunokhod/visitation.rb
146
+ - lunokhod.gemspec
147
+ - spec/lunokhod/error_report_spec.rb
148
+ - spec/lunokhod/parser_spec.rb
149
+ - spec/spec_helper.rb
150
+ homepage: https://github.com/NUBIC/lunokhod
151
+ licenses:
152
+ - MIT
153
+ post_install_message:
154
+ rdoc_options: []
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ none: false
159
+ requirements:
160
+ - - ! '>='
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ segments:
164
+ - 0
165
+ hash: -1254807072621896079
166
+ required_rubygems_version: !ruby/object:Gem::Requirement
167
+ none: false
168
+ requirements:
169
+ - - ! '>'
170
+ - !ruby/object:Gem::Version
171
+ version: 1.3.1
172
+ requirements: []
173
+ rubyforge_project:
174
+ rubygems_version: 1.8.25
175
+ signing_key:
176
+ specification_version: 3
177
+ summary: Parsing and compilation tools for Surveyor surveys
178
+ test_files:
179
+ - spec/lunokhod/error_report_spec.rb
180
+ - spec/lunokhod/parser_spec.rb
181
+ - spec/spec_helper.rb