sexpr 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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