sexpr 0.2.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.
Files changed (53) hide show
  1. data/CHANGELOG.md +13 -0
  2. data/Gemfile +8 -0
  3. data/Gemfile.lock +25 -0
  4. data/LICENCE.md +22 -0
  5. data/Manifest.txt +15 -0
  6. data/README.md +46 -0
  7. data/Rakefile +23 -0
  8. data/lib/sexpr.rb +31 -0
  9. data/lib/sexpr/alternative.rb +28 -0
  10. data/lib/sexpr/element.rb +9 -0
  11. data/lib/sexpr/grammar.rb +82 -0
  12. data/lib/sexpr/loader.rb +1 -0
  13. data/lib/sexpr/many.rb +52 -0
  14. data/lib/sexpr/reference.rb +30 -0
  15. data/lib/sexpr/rule.rb +29 -0
  16. data/lib/sexpr/sequence.rb +28 -0
  17. data/lib/sexpr/terminal.rb +35 -0
  18. data/lib/sexpr/version.rb +14 -0
  19. data/sexpr.gemspec +188 -0
  20. data/sexpr.noespec +25 -0
  21. data/spec/alternative/test_eat.rb +20 -0
  22. data/spec/alternative/test_match_q.rb +20 -0
  23. data/spec/bool_expr.yml +19 -0
  24. data/spec/grammar.yml +24 -0
  25. data/spec/grammar/test_compile_rule.rb +25 -0
  26. data/spec/grammar/test_compile_rule_defn.rb +98 -0
  27. data/spec/grammar/test_fetch.rb +18 -0
  28. data/spec/grammar/test_parse.rb +32 -0
  29. data/spec/grammar/test_root.rb +20 -0
  30. data/spec/many/test_eat.rb +59 -0
  31. data/spec/many/test_initialize.rb +36 -0
  32. data/spec/many/test_match_q.rb +24 -0
  33. data/spec/reference/test_eat.rb +13 -0
  34. data/spec/reference/test_match_q.rb +20 -0
  35. data/spec/rule/test_eat.rb +21 -0
  36. data/spec/rule/test_match_q.rb +24 -0
  37. data/spec/sequence/test_eat.rb +20 -0
  38. data/spec/sequence/test_match_q.rb +25 -0
  39. data/spec/spec_helper.rb +3 -0
  40. data/spec/terminal/test_eat.rb +20 -0
  41. data/spec/terminal/test_match_q.rb +56 -0
  42. data/spec/terminal/test_terminal_match.rb +89 -0
  43. data/spec/test_bool_expr.rb +27 -0
  44. data/spec/test_load.rb +35 -0
  45. data/spec/test_readme_examples.rb +44 -0
  46. data/spec/test_sexpr.rb +8 -0
  47. data/tasks/debug_mail.rake +75 -0
  48. data/tasks/debug_mail.txt +13 -0
  49. data/tasks/gem.rake +68 -0
  50. data/tasks/spec_test.rake +71 -0
  51. data/tasks/unit_test.rake +76 -0
  52. data/tasks/yard.rake +51 -0
  53. metadata +173 -0
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ describe Grammar, "fetch" do
4
+
5
+ let(:grammar){
6
+ Sexpr.load(:terminal => /[a-z]+/)
7
+ }
8
+
9
+ it 'returns the rule when it exists' do
10
+ grammar[:terminal].should be_a(Terminal)
11
+ end
12
+
13
+ it 'returns nil otherwise' do
14
+ grammar[:nosuchone].should be_nil
15
+ end
16
+
17
+ end
18
+ end # module Sexpr
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ describe Grammar, "parse" do
4
+
5
+ def parser
6
+ Object.new.tap{|x|
7
+ def x.parse(s)
8
+ Struct.new(:value).new([:parsed, s])
9
+ end
10
+ }
11
+ end
12
+
13
+ def grammar(options = {})
14
+ Sexpr.load({}, {:parser => parser})
15
+ end
16
+
17
+ it 'it accepts a string' do
18
+ grammar.parse("Hello world").should eq([:parsed, "Hello world"])
19
+ end
20
+
21
+ it 'it accepts a path' do
22
+ grammar.parse(Path.here).should eq([:parsed, File.read(__FILE__)])
23
+ end
24
+
25
+ it 'it accepts an IO' do
26
+ File.open(__FILE__, 'r') do |io|
27
+ grammar.parse(io).should eq([:parsed, File.read(__FILE__)])
28
+ end
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ describe Grammar, "root" do
4
+
5
+ let(:rules){ {:t => /[a-z]+/, :nt => true} }
6
+
7
+ def grammar(options = {})
8
+ Sexpr.load(rules, options)
9
+ end
10
+
11
+ it 'is the first key by default' do
12
+ grammar.root.value.should eq(/[a-z]+/)
13
+ end
14
+
15
+ it 'is the specified rule when specified' do
16
+ grammar(:root => :nt).root.value.should eq(true)
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ describe Many, "eat" do
4
+
5
+ let(:term){ Terminal.new(/^[a-z]+$/) }
6
+ let(:rule){ Many.new term, min, max }
7
+
8
+ context "when set for *" do
9
+ let(:min){ 0 }
10
+ let(:max){ nil }
11
+
12
+ it 'returns the subarray when zero match' do
13
+ rule.eat([nil, "world", "then"]).should eq([nil, "world", "then"])
14
+ end
15
+
16
+ it 'returns the subarray when one match' do
17
+ rule.eat(["world", nil, "then"]).should eq([nil, "then"])
18
+ end
19
+
20
+ it 'returns the subarray when multiple matches' do
21
+ rule.eat(["world", "then"]).should eq([])
22
+ end
23
+
24
+ end # *
25
+
26
+ context "when set for +" do
27
+ let(:min){ 1 }
28
+ let(:max){ nil }
29
+
30
+ it 'returns nil zero match' do
31
+ rule.eat([nil, "world", "then"]).should be_nil
32
+ end
33
+
34
+ it 'returns the subarray when one match' do
35
+ rule.eat(["world", nil, "then"]).should eq([nil, "then"])
36
+ end
37
+
38
+ it 'returns the subarray when multiple matches' do
39
+ rule.eat(["world", "then"]).should eq([])
40
+ end
41
+
42
+ end # +
43
+
44
+ context "when set for ?" do
45
+ let(:min){ 0 }
46
+ let(:max){ 1 }
47
+
48
+ it 'returns the subarray when zero match' do
49
+ rule.eat([nil, "world", "then"]).should eq([nil, "world", "then"])
50
+ end
51
+
52
+ it 'returns the subarray when one match' do
53
+ rule.eat(["world", "then"]).should eq(["then"])
54
+ end
55
+
56
+ end # ?
57
+
58
+ end
59
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ describe Many, "initialize" do
4
+
5
+ it 'understands a single min' do
6
+ many = Many.new(nil, 2)
7
+ many.min.should eq(2)
8
+ many.max.should be_nil
9
+ end
10
+
11
+ it 'understands a min and a max' do
12
+ many = Many.new(nil, 2, 10)
13
+ many.min.should eq(2)
14
+ many.max.should eq(10)
15
+ end
16
+
17
+ it 'understands ?' do
18
+ many = Many.new(nil, '?')
19
+ many.min.should eq(0)
20
+ many.max.should eq(1)
21
+ end
22
+
23
+ it 'understands *' do
24
+ many = Many.new(nil, '*')
25
+ many.min.should eq(0)
26
+ many.max.should be_nil
27
+ end
28
+
29
+ it 'understands +' do
30
+ many = Many.new(nil, '+')
31
+ many.min.should eq(1)
32
+ many.max.should be_nil
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ describe Many do
4
+
5
+ let(:term){ Terminal.new(/^[a-z]+$/) }
6
+ let(:rule){ Many.new term, '+' }
7
+
8
+ it 'returns true on match' do
9
+ rule.should be_match(["hello"])
10
+ rule.should be_match(["hello", "world"])
11
+ end
12
+
13
+ it 'returns false on partial match' do
14
+ rule.should_not be_match(["hello", "world", "12"])
15
+ end
16
+
17
+ it 'returns false on no match' do
18
+ rule.should_not be_match(["12"])
19
+ rule.should_not be_match([])
20
+ rule.should_not be_match(nil)
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ describe Reference, "eat" do
4
+
5
+ let(:grammar){ {:hello => Terminal.new(/^[a-z]+$/)} }
6
+ let(:rule) { Reference.new :hello, grammar }
7
+
8
+ it 'delegates the call' do
9
+ rule.eat(["hello", "world"]).should eq(["world"])
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ describe Reference, "match?" do
4
+
5
+ let(:grammar){ {:hello => Terminal.new(/^[a-z]+$/)} }
6
+ let(:rule) { Reference.new :hello, grammar }
7
+
8
+ it 'returns true on match' do
9
+ rule.should be_match("hello")
10
+ (rule === "hello").should be_true
11
+ end
12
+
13
+ it 'returns false on no match' do
14
+ rule.should_not be_match("12")
15
+ rule.should_not be_match(nil)
16
+ rule.should_not be_match([])
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ describe Rule, "eat" do
4
+
5
+ let(:defn){ Sequence.new [Terminal.new(/^[a-z]+$/)] }
6
+ let(:rule){ Rule.new :hello, defn }
7
+
8
+ it 'returns the trailing array when match' do
9
+ rule.eat([[:hello, "world"], "!"]).should eq(["!"])
10
+ end
11
+
12
+ it 'returns nil when not match' do
13
+ rule.eat([:hello, "world"]).should be_nil
14
+ rule.eat([:hello]).should be_nil
15
+ rule.eat([]).should be_nil
16
+ rule.eat([[]]).should be_nil
17
+ rule.eat([nil]).should be_nil
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ describe Rule, 'match?' do
4
+
5
+ let(:defn){ Sequence.new [Terminal.new(/^[a-z]+$/)] }
6
+ let(:rule){ Rule.new :hello, defn }
7
+
8
+ it 'returns true on match' do
9
+ rule.should be_match([:hello, "hello"])
10
+ end
11
+
12
+ it 'returns false on partial match' do
13
+ rule.should_not be_match([:hello, "hello", "world"])
14
+ end
15
+
16
+ it 'returns false on no match' do
17
+ rule.should_not be_match(["hello"])
18
+ rule.should_not be_match([:hello, 12])
19
+ rule.should_not be_match([])
20
+ rule.should_not be_match(nil)
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ describe Sequence, "eat" do
4
+
5
+ let(:alt1){ Terminal.new(nil) }
6
+ let(:alt2){ Terminal.new(/^[a-z]+$/) }
7
+ let(:rule){ Sequence.new [alt1, alt2] }
8
+
9
+ it 'returns the subarray when match' do
10
+ rule.eat([nil, "world", "then"]).should eq(["then"])
11
+ end
12
+
13
+ it 'returns nil when no match' do
14
+ rule.eat([]).should be_nil
15
+ rule.eat(["12"]).should be_nil
16
+ rule.eat([nil]).should be_nil
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ describe Sequence, 'match?' do
4
+
5
+ let(:alt1){ Terminal.new(nil) }
6
+ let(:alt2){ Terminal.new(/^[a-z]+$/) }
7
+ let(:rule){ Sequence.new [alt1, alt2] }
8
+
9
+ it 'returns true on match' do
10
+ rule.should be_match([nil, "hello"])
11
+ end
12
+
13
+ it 'returns false on partial match' do
14
+ rule.should_not be_match([nil, "hello", "world"])
15
+ end
16
+
17
+ it 'returns false on no match' do
18
+ rule.should_not be_match([:hello, 12])
19
+ rule.should_not be_match([])
20
+ rule.should_not be_match(nil)
21
+ rule.should_not be_match([nil])
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'epath'
3
+ require 'sexpr'
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ describe Terminal, "eat" do
4
+
5
+ let(:rule){ Terminal.new(/^[a-z]+$/) }
6
+
7
+ context "with a regexp" do
8
+
9
+ it 'returns subarray when match' do
10
+ rule.eat(["hello", "world"]).should eq(["world"])
11
+ end
12
+
13
+ it 'returns nil when no match' do
14
+ rule.eat([]).should be_nil
15
+ rule.eat(["12"]).should be_nil
16
+ end
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ describe Terminal, "match?" do
4
+
5
+ let(:rule){ Terminal.new(arg) }
6
+
7
+ describe "with true" do
8
+ let(:arg){ true }
9
+
10
+ it 'returns true on match' do
11
+ rule.should be_match(true)
12
+ (rule === true).should be_true
13
+ end
14
+
15
+ it 'returns false on no match' do
16
+ rule.should_not be_match([])
17
+ rule.should_not be_match(nil)
18
+ rule.should_not be_match(false)
19
+ end
20
+
21
+ end
22
+
23
+ describe "with false" do
24
+ let(:arg){ false }
25
+
26
+ it 'returns true on match' do
27
+ rule.should be_match(false)
28
+ (rule === false).should be_true
29
+ end
30
+
31
+ it 'returns false on no match' do
32
+ rule.should_not be_match([])
33
+ rule.should_not be_match(nil)
34
+ rule.should_not be_match(true)
35
+ end
36
+
37
+ end
38
+
39
+ describe "with nil" do
40
+ let(:arg){ nil }
41
+
42
+ it 'returns true on match' do
43
+ rule.should be_match(nil)
44
+ (rule === nil).should be_true
45
+ end
46
+
47
+ it 'returns false on no match' do
48
+ rule.should_not be_match([])
49
+ rule.should_not be_match(false)
50
+ rule.should_not be_match(true)
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ describe Terminal, "terminal_match?" do
4
+
5
+ before do
6
+ class Terminal; public :terminal_match?; end
7
+ end
8
+
9
+ let(:terminal){ Terminal.new(arg) }
10
+
11
+ context "with a Regexp" do
12
+ let(:arg){ /^[a-z]+$/ }
13
+
14
+ it 'matches a matching string' do
15
+ terminal.terminal_match?("hello").should be_true
16
+ end
17
+
18
+ it 'matches a non matching string' do
19
+ terminal.terminal_match?("12").should be_false
20
+ end
21
+
22
+ it 'does not match a sexp' do
23
+ terminal.terminal_match?([:sexp, "Hello World"]).should be_false
24
+ end
25
+
26
+ it 'does not match nil' do
27
+ terminal.terminal_match?(nil).should be_false
28
+ end
29
+ end
30
+
31
+ context "with true" do
32
+ let(:arg){ true }
33
+
34
+ it 'matches true' do
35
+ terminal.terminal_match?(true).should be_true
36
+ end
37
+
38
+ it 'does not match false/nil' do
39
+ terminal.terminal_match?(false).should be_false
40
+ terminal.terminal_match?(nil).should be_false
41
+ end
42
+
43
+ it 'does not match anything else' do
44
+ terminal.terminal_match?([]).should be_false
45
+ terminal.terminal_match?([:sexp]).should be_false
46
+ terminal.terminal_match?("true").should be_false
47
+ end
48
+ end
49
+
50
+ context "with false" do
51
+ let(:arg){ false }
52
+
53
+ it 'matches false' do
54
+ terminal.terminal_match?(false).should be_true
55
+ end
56
+
57
+ it 'does not match true/nil' do
58
+ terminal.terminal_match?(true).should be_false
59
+ terminal.terminal_match?(nil).should be_false
60
+ end
61
+
62
+ it 'does not match anything else' do
63
+ terminal.terminal_match?([]).should be_false
64
+ terminal.terminal_match?([:sexp]).should be_false
65
+ terminal.terminal_match?("false").should be_false
66
+ end
67
+ end
68
+
69
+ context "with nil" do
70
+ let(:arg){ nil }
71
+
72
+ it 'matches nil' do
73
+ terminal.terminal_match?(nil).should be_true
74
+ end
75
+
76
+ it 'does not match true/false' do
77
+ terminal.terminal_match?(true).should be_false
78
+ terminal.terminal_match?(false).should be_false
79
+ end
80
+
81
+ it 'does not match anything else' do
82
+ terminal.terminal_match?([]).should be_false
83
+ terminal.terminal_match?([:sexp]).should be_false
84
+ terminal.terminal_match?("nil").should be_false
85
+ end
86
+ end
87
+
88
+ end
89
+ end