sexpr 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/CHANGELOG.md +16 -0
  2. data/Gemfile +3 -3
  3. data/Gemfile.lock +14 -14
  4. data/Rakefile +0 -4
  5. data/examples/bool_expr/bool_expr.rb +1 -95
  6. data/lib/sexpr/grammar/matching.rb +3 -3
  7. data/lib/sexpr/grammar/parsing.rb +1 -1
  8. data/lib/sexpr/grammar/tagging.rb +16 -13
  9. data/lib/sexpr/loader.rb +1 -0
  10. data/lib/sexpr/matcher.rb +3 -2
  11. data/lib/sexpr/matcher/many.rb +16 -1
  12. data/lib/sexpr/matcher/non_terminal.rb +31 -0
  13. data/lib/sexpr/matcher/rule.rb +3 -6
  14. data/lib/sexpr/node.rb +1 -1
  15. data/lib/sexpr/parser.rb +1 -1
  16. data/lib/sexpr/processor.rb +11 -1
  17. data/lib/sexpr/processor/helper.rb +1 -1
  18. data/lib/sexpr/processor/sexpr_coercions.rb +6 -14
  19. data/lib/sexpr/rewriter.rb +0 -8
  20. data/lib/sexpr/version.rb +3 -3
  21. data/sexpr.gemspec +3 -3
  22. data/sexpr.noespec +13 -6
  23. data/spec/integration/bool_expr/test_not_push.rb +38 -0
  24. data/spec/integration/bool_expr/test_parsing.rb +15 -0
  25. data/spec/integration/bool_expr/test_tagging.rb +25 -0
  26. data/spec/integration/bool_expr/test_validation.rb +15 -0
  27. data/spec/{test_readme_examples.rb → integration/test_readme_examples.rb} +0 -0
  28. data/spec/spec_helper.rb +1 -1
  29. data/spec/unit/grammar/matching/test_compile_rule.rb +55 -0
  30. data/spec/{grammar → unit/grammar}/matching/test_compile_rule_defn.rb +0 -0
  31. data/spec/unit/grammar/matching/test_compile_rules.rb +45 -0
  32. data/spec/{grammar → unit/grammar}/options/test_install_parser.rb +0 -0
  33. data/spec/{grammar → unit/grammar}/options/test_install_path.rb +0 -0
  34. data/spec/{grammar → unit/grammar}/options/test_install_root.rb +0 -0
  35. data/spec/{grammar → unit/grammar}/tagging/test_looks_a_sexpr.rb +0 -0
  36. data/spec/{grammar → unit/grammar}/tagging/test_mod2rulename.rb +0 -0
  37. data/spec/{grammar → unit/grammar}/tagging/test_rule2modname.rb +0 -0
  38. data/spec/{grammar → unit/grammar}/tagging/test_tag_sexpr.rb +0 -0
  39. data/spec/unit/grammar/tagging/test_tagging_module_for.rb +72 -0
  40. data/spec/{grammar → unit/grammar}/test_new.rb +0 -0
  41. data/spec/{grammar → unit/grammar}/test_parse.rb +0 -0
  42. data/spec/{grammar → unit/grammar}/test_sexpr.rb +0 -0
  43. data/spec/{matcher → unit/matcher}/alternative/test_eat.rb +1 -1
  44. data/spec/{matcher → unit/matcher}/alternative/test_match_q.rb +0 -0
  45. data/spec/{matcher → unit/matcher}/many/test_eat.rb +0 -0
  46. data/spec/{matcher → unit/matcher}/many/test_initialize.rb +0 -0
  47. data/spec/{matcher → unit/matcher}/many/test_match_q.rb +0 -0
  48. data/spec/unit/matcher/non_terminal/test_eat.rb +31 -0
  49. data/spec/unit/matcher/non_terminal/test_match_q.rb +32 -0
  50. data/spec/{matcher → unit/matcher}/reference/test_eat.rb +0 -0
  51. data/spec/{matcher → unit/matcher}/reference/test_match_q.rb +0 -0
  52. data/spec/unit/matcher/rule/test_eat.rb +17 -0
  53. data/spec/unit/matcher/rule/test_match_q.rb +17 -0
  54. data/spec/{matcher → unit/matcher}/sequence/test_eat.rb +0 -0
  55. data/spec/{matcher → unit/matcher}/sequence/test_match_q.rb +0 -0
  56. data/spec/{matcher → unit/matcher}/terminal/test_eat.rb +1 -1
  57. data/spec/{matcher → unit/matcher}/terminal/test_match_q.rb +0 -0
  58. data/spec/{matcher → unit/matcher}/terminal/test_terminal_match.rb +0 -0
  59. data/spec/{node → unit/node}/test_sexpr_body.rb +0 -0
  60. data/spec/{node → unit/node}/test_sexpr_copy.rb +0 -0
  61. data/spec/{node → unit/node}/test_sexpr_type.rb +0 -0
  62. data/spec/{node → unit/node}/test_tracking_markers.rb +0 -0
  63. data/spec/{parser → unit/parser}/citrus/test_new.rb +0 -0
  64. data/spec/{parser → unit/parser}/citrus/test_parse.rb +0 -0
  65. data/spec/{parser → unit/parser}/citrus/test_recognize.rb +0 -0
  66. data/spec/{parser → unit/parser}/citrus/test_registration.rb +0 -0
  67. data/spec/{parser → unit/parser}/citrus/test_to_sexpr.rb +0 -0
  68. data/spec/{parser → unit/parser}/test_factor.rb +0 -0
  69. data/spec/{parser → unit/parser}/test_input_text.rb +0 -0
  70. data/spec/{processor → unit/processor}/helper/test_call.rb +0 -0
  71. data/spec/{processor → unit/processor}/test_apply.rb +0 -0
  72. data/spec/{processor → unit/processor}/test_build_helper_chain.rb +0 -0
  73. data/spec/{processor → unit/processor}/test_call.rb +0 -0
  74. data/spec/unit/processor/test_grammar.rb +56 -0
  75. data/spec/{processor → unit/processor}/test_helper.rb +0 -0
  76. data/spec/{processor → unit/processor}/test_sexpr_coercions.rb +6 -2
  77. data/spec/{processor → unit/processor}/test_use.rb +0 -0
  78. data/spec/{rewriter → unit/rewriter}/test_copy_and_apply.rb +0 -0
  79. data/spec/{test_load.rb → unit/test_load.rb} +3 -2
  80. data/spec/{test_rewriter.rb → unit/test_rewriter.rb} +0 -0
  81. data/spec/{test_sexpr.rb → unit/test_sexpr.rb} +1 -1
  82. data/tasks/gem.rake +9 -4
  83. data/tasks/test.rake +26 -0
  84. metadata +163 -117
  85. data/spec/grammar/matching/test_compile_rule.rb +0 -23
  86. data/spec/matcher/rule/test_eat.rb +0 -21
  87. data/spec/matcher/rule/test_match_q.rb +0 -24
  88. data/tasks/spec_test.rake +0 -71
  89. data/tasks/unit_test.rake +0 -76
@@ -2,14 +2,6 @@ module Sexpr
2
2
  class Rewriter < Processor
3
3
  helper SexprCoercions
4
4
 
5
- def self.grammar(sexpr_grammar)
6
- @sexpr_grammar = sexpr_grammar
7
- end
8
-
9
- def sexpr_grammar
10
- (self.class.instance_variable_get(:"@sexpr_grammar") || super) rescue Sexpr
11
- end
12
-
13
5
  def copy_and_apply(sexpr)
14
6
  sexpr.sexpr_copy do |copy, child|
15
7
  copy << (Sexpr===child ? apply(child) : child)
@@ -2,8 +2,8 @@ module Sexpr
2
2
  module Version
3
3
 
4
4
  MAJOR = 0
5
- MINOR = 5
6
- TINY = 1
5
+ MINOR = 6
6
+ TINY = 0
7
7
 
8
8
  def self.to_s
9
9
  [ MAJOR, MINOR, TINY ].join('.')
@@ -11,4 +11,4 @@ module Sexpr
11
11
 
12
12
  end
13
13
  VERSION = Version.to_s
14
- end
14
+ end
@@ -123,10 +123,10 @@ Gem::Specification.new do |s|
123
123
  # One call to add_development_dependency('gem_name', 'gem version requirement')
124
124
  # for each development dependency. These gems are required for developers
125
125
  #
126
- s.add_development_dependency("epath", "~> 0.0.1")
126
+ s.add_development_dependency("path", "~> 1.3")
127
127
  s.add_development_dependency("citrus", "~> 2.4")
128
- s.add_development_dependency("rake", "~> 0.9.2")
129
- s.add_development_dependency("rspec", "~> 2.8")
128
+ s.add_development_dependency("rake", "~> 10.0")
129
+ s.add_development_dependency("rspec", "~> 2.10")
130
130
  s.add_development_dependency("wlang", "~> 0.10.2")
131
131
 
132
132
 
@@ -1,15 +1,22 @@
1
1
  template-info:
2
- name: "ruby"
3
- version: 1.7.3
2
+ name: "rubygem.noe"
3
+ version: 2.0.1
4
4
  links:
5
5
  source: https://github.com/blambeau/noe
6
+ manifest:
7
+ tasks/unit_test.rake:
8
+ ignore: true
9
+ safe_override: false
10
+ tasks/spec_test.rake:
11
+ ignore: true
12
+ safe_override: false
6
13
  variables:
7
14
  lower:
8
15
  sexpr
9
16
  upper:
10
17
  Sexpr
11
18
  version:
12
- 0.5.1
19
+ 0.6.0
13
20
  summary: |-
14
21
  A compilation framework around s-expressions
15
22
  description: |-
@@ -19,8 +26,8 @@ variables:
19
26
  links:
20
27
  - https://github.com/blambeau/sexp
21
28
  dependencies:
22
- - {name: epath, version: "~> 0.0.1", groups: [development]}
29
+ - {name: path, version: "~> 1.3", groups: [development]}
23
30
  - {name: citrus, version: "~> 2.4", groups: [development]}
24
- - {name: rake, version: "~> 0.9.2", groups: [development]}
25
- - {name: rspec, version: "~> 2.8", groups: [development]}
31
+ - {name: rake, version: "~> 10.0", groups: [development]}
32
+ - {name: rspec, version: "~> 2.10", groups: [development]}
26
33
  - {name: wlang, version: "~> 0.10.2", groups: [development]}
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ describe BoolExpr::NotPushProcessor do
3
+ subject{ BoolExpr }
4
+
5
+ def _(expr)
6
+ BoolExpr.sexpr(expr)
7
+ end
8
+
9
+ def rw(expr)
10
+ BoolExpr::NotPushProcessor.new.call(expr)
11
+ end
12
+
13
+ it 'does nothing on variable references' do
14
+ rw("not x").should eq([:bool_not, [:var_ref, "x"]])
15
+ end
16
+
17
+ it 'rewrites literals through negating them' do
18
+ rw("not true").should eq(_ "false")
19
+ rw("not false").should eq(_ "true")
20
+ end
21
+
22
+ it 'rewrites not through removing them' do
23
+ rw("not not true").should eq(_ "true")
24
+ end
25
+
26
+ it 'rewrites or through and of negated terms' do
27
+ rw("not(x or y)").should eq(_ "not(x) and not(y)")
28
+ end
29
+
30
+ it 'rewrites and through or of negated terms' do
31
+ rw("not(x and y)").should eq(_ "not(x) or not(y)")
32
+ end
33
+
34
+ it 'rewrites recursively' do
35
+ rw("not(x and not(y))").should eq(_ "not(x) or y")
36
+ end
37
+
38
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+ describe BoolExpr, "the parsing feature" do
3
+ subject{ BoolExpr }
4
+
5
+ it 'parses boolean expressions without error' do
6
+ subject.parse("x and y").should be_a(Citrus::Match)
7
+ subject.parse("not(y)").should be_a(Citrus::Match)
8
+ subject.parse("not(true)").should be_a(Citrus::Match)
9
+ end
10
+
11
+ it 'provides a shortcut to get s-expressions directly' do
12
+ subject.sexpr("x and y").should eq([:bool_and, [:var_ref, "x"], [:var_ref, "y"]])
13
+ end
14
+
15
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+ describe BoolExpr, "the tagging feature" do
3
+ subject{ BoolExpr }
4
+
5
+ it 'tags parsing results with the Sexpr module' do
6
+ sexpr = subject.sexpr("x and y")
7
+ sexpr.should be_a(Sexpr)
8
+ sexpr.sexpr_type.should eq(:bool_and)
9
+ sexpr.sexpr_body.should eq([[:var_ref, "x"], [:var_ref, "y"]])
10
+ end
11
+
12
+ it 'tags parsing results with user modules' do
13
+ subject.sexpr("x and y").should be_a(BoolExpr::And)
14
+ end
15
+
16
+ it 'allows tagging manually' do
17
+ subject.sexpr([:bool_lit, true]).should be_a(BoolExpr::Lit)
18
+ end
19
+
20
+ it 'applies tagging recursively' do
21
+ sexpr = subject.sexpr([:bool_not, [:bool_lit, true]])
22
+ sexpr.last.should be_a(BoolExpr::Lit)
23
+ end
24
+
25
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+ describe BoolExpr, 'the validation feature' do
3
+ subject{ BoolExpr }
4
+
5
+ it 'validates s-expressions' do
6
+ subject.match?([:bool_lit, true]).should be_true
7
+ subject.match?([:bool_lit, "x"]).should be_false
8
+ end
9
+
10
+ it 'validates s-expressions against specific rules' do
11
+ subject[:bool_lit].match?([:bool_lit, true]).should be_true
12
+ subject[:bool_and].match?([:bool_lit, true]).should be_false
13
+ end
14
+
15
+ end
@@ -1,4 +1,4 @@
1
- require 'epath'
1
+ require 'path'
2
2
  root = Path.backfind('.[lib]')
3
3
 
4
4
  require 'citrus'
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ module Grammar
4
+ describe Matching, "compile_rule" do
5
+ include Matching
6
+
7
+ subject{ compile_rule(:hello, defn) }
8
+
9
+ shared_examples_for 'a terminal rule' do
10
+ it{ should be_a(Matcher::Rule) }
11
+
12
+ it 'should have the expected defn' do
13
+ subject.defn.should be(defn)
14
+ end
15
+
16
+ it 'should have the correct name' do
17
+ subject.name.should eq(:hello)
18
+ end
19
+ end
20
+
21
+ shared_examples_for 'a non-terminal rule' do
22
+ it{ should be_a(Matcher::Rule) }
23
+
24
+ it 'should have the expected non-terminal' do
25
+ subject.defn.should be_a(Matcher::NonTerminal)
26
+ subject.defn.name.should eq(:hello)
27
+ subject.defn.defn.should be(defn)
28
+ end
29
+
30
+ it 'should have the correct name' do
31
+ subject.name.should eq(:hello)
32
+ end
33
+ end
34
+
35
+ context 'on Alternative' do
36
+ let(:defn){ Matcher::Alternative.new([]) }
37
+
38
+ it_should_behave_like "a terminal rule"
39
+ end
40
+
41
+ context 'on Terminal' do
42
+ let(:defn){ Matcher::Terminal.new(true) }
43
+
44
+ it_should_behave_like "a terminal rule"
45
+ end
46
+
47
+ context 'on Sequence' do
48
+ let(:defn){ Matcher::Sequence.new([]) }
49
+
50
+ it_should_behave_like "a non-terminal rule"
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ module Grammar
4
+ describe Matching, "compile_rules" do
5
+ include Matching
6
+
7
+ let(:yaml){
8
+ <<-YAML
9
+ bool_and:
10
+ - [ bool_lit, bool_lit ]
11
+ bool_lit:
12
+ - true
13
+ - false
14
+ var_name:
15
+ !ruby/regexp /^[a-z]+$/
16
+ YAML
17
+ }
18
+
19
+ let(:rules){
20
+ YAML.load(yaml)
21
+ }
22
+
23
+ subject{ compile_rules(rules) }
24
+
25
+ it{ should be_a(Hash) }
26
+
27
+ it 'has expected keys' do
28
+ subject.keys.should eq([:bool_and, :bool_lit, :var_name])
29
+ end
30
+
31
+ it 'has expected values' do
32
+ subject.values.each do |val|
33
+ val.should be_a(Matcher::Rule)
34
+ end
35
+ end
36
+
37
+ it 'has expected defn' do
38
+ subject[:bool_and].defn.should be_a(Matcher::NonTerminal)
39
+ subject[:bool_lit].defn.should be_a(Matcher::Alternative)
40
+ subject[:var_name].defn.should be_a(Matcher::Terminal)
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+ module Sexpr::Grammar
3
+ describe Tagging, "tagging_module_for" do
4
+ include Tagging
5
+
6
+ module TaggingReference
7
+ module Node; end
8
+ module Not; end
9
+ module Lit; end
10
+ end
11
+
12
+ subject{ tagging_module_for(rulename) }
13
+
14
+ context 'when there is a tagging reference and a default tagging module' do
15
+
16
+ def tagging_reference
17
+ TaggingReference
18
+ end
19
+
20
+ def default_tagging_module
21
+ TaggingReference::Node
22
+ end
23
+
24
+ context 'when the module exists' do
25
+ let(:rulename){ :not }
26
+
27
+ it{ should be(TaggingReference::Not) }
28
+ end
29
+
30
+ context 'when the module does not exists' do
31
+ let(:rulename){ :blah }
32
+
33
+ it{ should be(TaggingReference::Node) }
34
+ end
35
+ end
36
+
37
+ context 'when there is a no tagging reference but default tagging module' do
38
+
39
+ def default_tagging_module
40
+ TaggingReference::Node
41
+ end
42
+
43
+ let(:rulename){ :not }
44
+
45
+ it{ should be(TaggingReference::Node) }
46
+ end
47
+
48
+ context 'when there is a a tagging reference and no default tagging module' do
49
+
50
+ def tagging_reference
51
+ TaggingReference
52
+ end
53
+
54
+ def default_tagging_module
55
+ nil
56
+ end
57
+
58
+ context 'when the module exists' do
59
+ let(:rulename){ :not }
60
+
61
+ it{ should be(TaggingReference::Not) }
62
+ end
63
+
64
+ context 'when the module does not exists' do
65
+ let(:rulename){ :blah }
66
+
67
+ it{ should be_nil }
68
+ end
69
+ end
70
+
71
+ end
72
+ end
@@ -17,4 +17,4 @@ module Sexpr::Matcher
17
17
  end
18
18
 
19
19
  end
20
- end
20
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ module Sexpr::Matcher
3
+ describe NonTerminal, "eat" do
4
+
5
+ let(:defn){ Sequence.new [Terminal.new(/^[a-z]+$/)] }
6
+ let(:rule){ NonTerminal.new :hello, defn }
7
+
8
+ subject{ rule.eat(sexpr) }
9
+
10
+ context 'when match' do
11
+ let(:sexpr){ [[:hello, "world"], "!"] }
12
+
13
+ it{ should eq(["!"]) }
14
+ end
15
+
16
+ [
17
+ [:hello, "world"],
18
+ [:hello],
19
+ [],
20
+ [[]],
21
+ [nil],
22
+ ].each do |example|
23
+ context "when no match, e.g. #{example.inspect}" do
24
+ let(:sexpr){ example }
25
+
26
+ it{ should be_nil }
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+ module Sexpr::Matcher
3
+ describe NonTerminal, "match?" do
4
+
5
+ let(:defn){ Sequence.new [Terminal.new(/^[a-z]+$/)] }
6
+ let(:rule){ NonTerminal.new :hello, defn }
7
+
8
+ subject{ rule.match?(sexpr) }
9
+
10
+ context 'when match' do
11
+ let(:sexpr){ [:hello, "world"] }
12
+
13
+ it{ should be_true }
14
+ end
15
+
16
+ [
17
+ [[:hello, "world"]],
18
+ [:hello],
19
+ [],
20
+ [[]],
21
+ [nil],
22
+ nil
23
+ ].each do |example|
24
+ context "when no match, e.g. #{example.inspect}" do
25
+ let(:sexpr){ example }
26
+
27
+ it{ should be_false }
28
+ end
29
+ end
30
+
31
+ end
32
+ end