sexpr 0.4.0 → 0.5.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/CHANGELOG.md +56 -17
- data/Gemfile +1 -1
- data/Gemfile.lock +1 -1
- data/README.md +3 -0
- data/Rakefile +0 -8
- data/examples/bool_expr/bool_expr.rb +3 -3
- data/lib/sexpr/grammar/tagging.rb +19 -10
- data/lib/sexpr/processor.rb +58 -20
- data/lib/sexpr/rewriter.rb +1 -1
- data/lib/sexpr/version.rb +1 -1
- data/sexpr.gemspec +1 -1
- data/sexpr.noespec +3 -3
- data/spec/fixtures/bar.rb +9 -0
- data/spec/fixtures/foo.rb +14 -0
- data/spec/fixtures/preprocessed.rb +33 -0
- data/spec/fixtures/simple_processor.rb +19 -0
- data/spec/grammar/tagging/test_tag_sexpr.rb +32 -7
- data/spec/processor/test_apply.rb +34 -0
- data/spec/processor/test_call.rb +30 -29
- data/spec/processor/test_use.rb +22 -0
- data/spec/spec_helper.rb +1 -21
- metadata +25 -18
- data/spec/processor/test_main_processor.rb +0 -18
data/CHANGELOG.md
CHANGED
@@ -1,14 +1,53 @@
|
|
1
|
+
# 0.5.0 / 2012-02-25
|
2
|
+
|
3
|
+
* Major enhancements
|
4
|
+
|
5
|
+
* `Processor#apply` is introduced and is intended to be used to apply processing rules
|
6
|
+
from the inside of the processor class. This method is equivalent to `#call` when no
|
7
|
+
preprocessor is installed (see below).
|
8
|
+
* Preprocessors can now be installed on a Processor through its `use` class method.
|
9
|
+
Preprocessors are applied ala 'Enumerable#inject' on the s-expression passed at
|
10
|
+
`Prcoessor#call`. The preprocessed result is then passed to `#apply` for further
|
11
|
+
processing by the processor itself.
|
12
|
+
(Please note that preprocessing is *not* performed by `#apply` itself; preprocessing
|
13
|
+
is typically applied once one the whole abstract syntax tree instead of successively
|
14
|
+
when its nodes are encountered. Tip: use helpers for such behavior).
|
15
|
+
* `Processor.use` can also be used to make specific computations ahead of processing
|
16
|
+
(such as a symbol table). For this, simply pass a Hash that maps a computation name
|
17
|
+
to a processor class. Attribute readers are automatically installed on the processor
|
18
|
+
class and instance variables set by `#call` accordingly.
|
19
|
+
(Please note such preprocessors do not participate to the rewriting chain described
|
20
|
+
above.)
|
21
|
+
|
22
|
+
* Minor enhancements
|
23
|
+
|
24
|
+
* `Processor.call(sexpr, opts)` is a shortcut for `Processor.new(opts).call(sexpr)`
|
25
|
+
* `Grammar#default_taggging_module` is introduced for cases where either no fine-grained
|
26
|
+
tagging is needed (e.g. all nodes tagged with the same Node module) or fine-grained
|
27
|
+
tagging is needed but is not a total function (e.g. not all nodes have a
|
28
|
+
specialization of Node).
|
29
|
+
|
30
|
+
* Bug fixes
|
31
|
+
|
32
|
+
* Processor options taken at construction are now correctly kept under @options (an
|
33
|
+
attribute reader is provided)
|
34
|
+
|
35
|
+
* Breaking changes
|
36
|
+
|
37
|
+
* The `Processor#main_processor` feature (undocumented and unused in examples) has been
|
38
|
+
removed. Using preprocessors is much cleaner that linking processors to each other.
|
39
|
+
|
1
40
|
# 0.4.0 / 2012-02-23
|
2
41
|
|
3
42
|
* Major enhancements
|
4
43
|
|
5
|
-
* A processing/rewriting framework has been added to Sexpr. See the `Processor` and
|
6
|
-
classes, as well as the boolean expression example.
|
7
|
-
* Tracking markers can now decorate s-expressions, provided they include the `Sexpr`
|
8
|
-
Tracking markers are a simple Hash of meta-information (i.e. not taken into
|
9
|
-
equality for s-expressions). Such markers can be set with
|
10
|
-
Default markers are typically provided by parsers for
|
11
|
-
with the source text it comes from.
|
44
|
+
* A processing/rewriting framework has been added to Sexpr. See the `Processor` and
|
45
|
+
`Rewriter` classes, as well as the boolean expression example.
|
46
|
+
* Tracking markers can now decorate s-expressions, provided they include the `Sexpr`
|
47
|
+
module. Tracking markers are a simple Hash of meta-information (i.e. not taken into
|
48
|
+
account for equality for s-expressions). Such markers can be set with
|
49
|
+
`Grammar#sexpr(sexpr, markers)`. Default markers are typically provided by parsers for
|
50
|
+
traceability of the s-expression with the source text it comes from.
|
12
51
|
|
13
52
|
* Minor enhancements
|
14
53
|
|
@@ -20,12 +59,12 @@
|
|
20
59
|
|
21
60
|
* Breaking changes
|
22
61
|
|
23
|
-
* `Parser.factor` does no longer accept options. This is to avoid the 'yet another
|
24
|
-
symptom and favor convention over configuration.
|
62
|
+
* `Parser.factor` does no longer accept options. This is to avoid the 'yet another
|
63
|
+
options' symptom and favor convention over configuration.
|
25
64
|
* Accordingly, `Sexpr::Citrus::Parser` no longer takes options at construction either.
|
26
|
-
* `Grammar#sexpr` does no longer allow parsing options as second argument, but takes
|
27
|
-
markers (see enhancements). To palliate to this, default parsing options can
|
28
|
-
specified through `Grammar#default_parse_options` (see enhancements).
|
65
|
+
* `Grammar#sexpr` does no longer allow parsing options as second argument, but takes
|
66
|
+
tracking markers (see enhancements). To palliate to this, default parsing options can
|
67
|
+
now be specified through `Grammar#default_parse_options` (see enhancements).
|
29
68
|
|
30
69
|
# 0.3.0 / 2012-02-21
|
31
70
|
|
@@ -44,11 +83,11 @@
|
|
44
83
|
the result to a constant makes perfect sense and benefits from the ruby's magic naming
|
45
84
|
feature.
|
46
85
|
* A loaded grammar now respond to a :sexpr method that parses (if needed) and returns a
|
47
|
-
s-expression. The latter, and all its sub-expressions are automatically tagged with
|
48
|
-
Sexpr module, as well as with user-defined modules. The latter are automatically
|
49
|
-
with a convention over configuration heuristics that associates rule names
|
50
|
-
That convention may however be overridden with specific grammar
|
51
|
-
example).
|
86
|
+
s-expression. The latter, and all its sub-expressions are automatically tagged with
|
87
|
+
the Sexpr module, as well as with user-defined modules. The latter are automatically
|
88
|
+
discovered with a convention over configuration heuristics that associates rule names
|
89
|
+
to module names. That convention may however be overridden with specific grammar
|
90
|
+
methods (see the BoolExpr example).
|
52
91
|
|
53
92
|
# 0.2.0 / 2012-02-21
|
54
93
|
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Sexpr
|
2
2
|
|
3
|
+
[](http://travis-ci.org/blambeau/sexpr)
|
4
|
+
[](https://gemnasium.com/blambeau/sexpr)
|
5
|
+
|
3
6
|
A ruby compilation framework around s-expressions.
|
4
7
|
|
5
8
|
## Links
|
data/Rakefile
CHANGED
@@ -1,11 +1,3 @@
|
|
1
|
-
begin
|
2
|
-
gem "bundler", "~> 1.0"
|
3
|
-
require "bundler/setup"
|
4
|
-
rescue LoadError => ex
|
5
|
-
puts ex.message
|
6
|
-
abort "Bundler failed to load, (did you run 'gem install bundler' ?)"
|
7
|
-
end
|
8
|
-
|
9
1
|
# Dynamically load the gem spec
|
10
2
|
$gemspec_file = File.expand_path('../sexpr.gemspec', __FILE__)
|
11
3
|
$gemspec = Kernel.eval(File.read($gemspec_file))
|
@@ -42,9 +42,9 @@ module BoolExpr
|
|
42
42
|
# cases
|
43
43
|
def on_bool_not(sexpr)
|
44
44
|
case expr = sexpr.last
|
45
|
-
when And then
|
46
|
-
when Or then
|
47
|
-
when Not then
|
45
|
+
when And then apply [:bool_or, [:bool_not, expr[1]], [:bool_not, expr[2]] ]
|
46
|
+
when Or then apply [:bool_and, [:bool_not, expr[1]], [:bool_not, expr[2]] ]
|
47
|
+
when Not then apply expr.last
|
48
48
|
when Lit then [:bool_lit, !expr.last]
|
49
49
|
else
|
50
50
|
sexpr
|
@@ -15,25 +15,29 @@ module Sexpr
|
|
15
15
|
nil
|
16
16
|
end
|
17
17
|
|
18
|
+
def default_tagging_module
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
18
22
|
def sexpr(input, markers = nil)
|
19
23
|
case input
|
20
24
|
when Array
|
21
|
-
tag_sexpr input,
|
25
|
+
tag_sexpr input, markers
|
22
26
|
else
|
23
27
|
sexpr = parser!.to_sexpr(parse(input))
|
24
|
-
tag_sexpr sexpr,
|
28
|
+
tag_sexpr sexpr, markers, true
|
25
29
|
end
|
26
30
|
end
|
27
31
|
|
28
32
|
private
|
29
33
|
|
30
|
-
def tag_sexpr(sexpr,
|
34
|
+
def tag_sexpr(sexpr, markers = nil, force = false)
|
31
35
|
return sexpr unless looks_a_sexpr?(sexpr)
|
32
36
|
return sexpr if Sexpr===sexpr and not(force) and markers.nil?
|
33
37
|
|
34
38
|
# set the Sexpr modules
|
35
39
|
sexpr.extend(Sexpr) unless Sexpr===sexpr
|
36
|
-
tag_sexpr_with_user_module(sexpr
|
40
|
+
tag_sexpr_with_user_module(sexpr)
|
37
41
|
|
38
42
|
# set the markers if any
|
39
43
|
if markers
|
@@ -43,16 +47,21 @@ module Sexpr
|
|
43
47
|
|
44
48
|
# recurse
|
45
49
|
sexpr[1..-1].each do |child|
|
46
|
-
tag_sexpr(child,
|
50
|
+
tag_sexpr(child, nil, force)
|
47
51
|
end
|
48
52
|
sexpr
|
49
53
|
end
|
50
54
|
|
51
|
-
def tag_sexpr_with_user_module(sexpr
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
55
|
+
def tag_sexpr_with_user_module(sexpr)
|
56
|
+
if ref = tagging_reference
|
57
|
+
rulename = sexpr.first
|
58
|
+
modname = rule2modname(rulename)
|
59
|
+
tag = ref.const_get(modname) rescue default_tagging_module
|
60
|
+
sexpr.extend(tag) if tag
|
61
|
+
elsif tag = default_tagging_module
|
62
|
+
sexpr.extend(tag)
|
63
|
+
end
|
64
|
+
sexpr
|
56
65
|
end
|
57
66
|
|
58
67
|
def looks_a_sexpr?(arg)
|
data/lib/sexpr/processor.rb
CHANGED
@@ -4,36 +4,53 @@ require_relative 'processor/sexpr_coercions'
|
|
4
4
|
module Sexpr
|
5
5
|
class Processor
|
6
6
|
|
7
|
-
|
7
|
+
class << self
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
def preprocessors
|
10
|
+
@preprocessors ||= superclass.preprocessors.dup rescue [ ]
|
11
|
+
end
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
13
|
+
def use(preprocessor, options = nil)
|
14
|
+
preprocessor.keys.each{|k| attr_reader(k)} if preprocessor.is_a?(Hash)
|
15
|
+
preprocessors << [preprocessor, options]
|
16
|
+
end
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
helpers[0...-1].reverse.inject(helpers.last.new) do |chain, h_class|
|
22
|
-
prepended = h_class.new
|
23
|
-
prepended.next_in_chain = chain
|
24
|
-
prepended
|
18
|
+
def helpers
|
19
|
+
@helpers ||= superclass.helpers.dup rescue [ ]
|
25
20
|
end
|
26
|
-
end
|
27
21
|
|
28
|
-
|
22
|
+
def helper(helper_class)
|
23
|
+
methods = helper_class.const_get(:Methods) rescue nil
|
24
|
+
module_eval{ include methods } if methods
|
25
|
+
helpers << helper_class
|
26
|
+
end
|
27
|
+
|
28
|
+
def build_helper_chain(helpers = self.helpers)
|
29
|
+
return NullHelper.new if helpers.empty?
|
30
|
+
helpers[0...-1].reverse.inject(helpers.last.new) do |chain, h_class|
|
31
|
+
prepended = h_class.new
|
32
|
+
prepended.next_in_chain = chain
|
33
|
+
prepended
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def call(sexpr, options = nil)
|
38
|
+
new(options).call(sexpr)
|
39
|
+
end
|
29
40
|
|
30
|
-
|
41
|
+
end # class << self
|
31
42
|
|
32
|
-
|
33
|
-
|
43
|
+
attr_reader :options
|
44
|
+
|
45
|
+
def initialize(options = nil)
|
46
|
+
@options = options || {}
|
34
47
|
end
|
35
48
|
|
36
49
|
def call(sexpr)
|
50
|
+
apply(preprocess(sexpr))
|
51
|
+
end
|
52
|
+
|
53
|
+
def apply(sexpr)
|
37
54
|
help(sexpr) do |n|
|
38
55
|
meth = :"on_#{n.first}"
|
39
56
|
meth = :"on_missing" unless respond_to?(meth)
|
@@ -47,6 +64,27 @@ module Sexpr
|
|
47
64
|
|
48
65
|
private
|
49
66
|
|
67
|
+
def preprocess(sexpr)
|
68
|
+
preprocessors = self.class.preprocessors
|
69
|
+
preprocessors.each do |pre|
|
70
|
+
sexpr = _preprocess(sexpr, pre)
|
71
|
+
end
|
72
|
+
sexpr
|
73
|
+
end
|
74
|
+
|
75
|
+
def _preprocess(sexpr, preprocessing)
|
76
|
+
pre_class, options = preprocessing
|
77
|
+
if Hash===pre_class
|
78
|
+
pre_class.each_pair do |k,v|
|
79
|
+
computed = v.new(options).call(sexpr)
|
80
|
+
self.instance_variable_set(:"@#{k}", computed)
|
81
|
+
end
|
82
|
+
sexpr
|
83
|
+
else
|
84
|
+
pre_class.new(options).call(sexpr)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
50
88
|
def helper_chain
|
51
89
|
@helper_chain ||= self.class.build_helper_chain
|
52
90
|
end
|
data/lib/sexpr/rewriter.rb
CHANGED
data/lib/sexpr/version.rb
CHANGED
data/sexpr.gemspec
CHANGED
@@ -126,7 +126,7 @@ Gem::Specification.new do |s|
|
|
126
126
|
s.add_development_dependency("epath", "~> 0.0.1")
|
127
127
|
s.add_development_dependency("citrus", "~> 2.4")
|
128
128
|
s.add_development_dependency("rake", "~> 0.9.2")
|
129
|
-
s.add_development_dependency("rspec", "~> 2.8
|
129
|
+
s.add_development_dependency("rspec", "~> 2.8")
|
130
130
|
s.add_development_dependency("wlang", "~> 0.10.2")
|
131
131
|
|
132
132
|
|
data/sexpr.noespec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
template-info:
|
2
2
|
name: "ruby"
|
3
|
-
version: 1.7.
|
3
|
+
version: 1.7.3
|
4
4
|
links:
|
5
5
|
source: https://github.com/blambeau/noe
|
6
6
|
variables:
|
@@ -9,7 +9,7 @@ variables:
|
|
9
9
|
upper:
|
10
10
|
Sexpr
|
11
11
|
version:
|
12
|
-
0.
|
12
|
+
0.5.0
|
13
13
|
summary: |-
|
14
14
|
A compilation framework around s-expressions
|
15
15
|
description: |-
|
@@ -22,5 +22,5 @@ variables:
|
|
22
22
|
- {name: epath, version: "~> 0.0.1", groups: [development]}
|
23
23
|
- {name: citrus, version: "~> 2.4", groups: [development]}
|
24
24
|
- {name: rake, version: "~> 0.9.2", groups: [development]}
|
25
|
-
- {name: rspec, version: "~> 2.8
|
25
|
+
- {name: rspec, version: "~> 2.8", groups: [development]}
|
26
26
|
- {name: wlang, version: "~> 0.10.2", groups: [development]}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Preprocessed < Sexpr::Processor
|
2
|
+
|
3
|
+
class Prefix < Sexpr::Processor
|
4
|
+
|
5
|
+
def on_missing(sexpr)
|
6
|
+
[ :"#{options[:prefix]}#{sexpr.first}" ] + sexpr[1..-1]
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
use Prefix, :prefix => "prefix_"
|
11
|
+
|
12
|
+
def on_prefix_hello(sexpr)
|
13
|
+
[:preprocessed_hello, sexpr]
|
14
|
+
end
|
15
|
+
|
16
|
+
def on_apply(sexpr)
|
17
|
+
apply(sexpr.last)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
class SubPreprocessed < Preprocessed
|
23
|
+
|
24
|
+
class Upcase < Sexpr::Processor
|
25
|
+
|
26
|
+
def call(sexpr)
|
27
|
+
sexpr.first.to_s.upcase
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
use :upcased => Upcase
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class SimpleProcessor < Sexpr::Processor
|
2
|
+
|
3
|
+
def on_hello(sexpr)
|
4
|
+
[:simple_hello, sexpr]
|
5
|
+
end
|
6
|
+
|
7
|
+
def on_missing(sexpr)
|
8
|
+
if sexpr.first == :simple_missing
|
9
|
+
[:simple_pass_missing, sexpr]
|
10
|
+
else
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def on_apply(sexpr)
|
16
|
+
apply(sexpr.last)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -4,24 +4,49 @@ module Sexpr::Grammar
|
|
4
4
|
include Tagging
|
5
5
|
|
6
6
|
module TaggingReference
|
7
|
+
module Node; end
|
7
8
|
module Not; end
|
8
9
|
module Lit; end
|
9
10
|
end
|
10
11
|
|
12
|
+
def default_tagging_module
|
13
|
+
TaggingReference::Node
|
14
|
+
end
|
15
|
+
|
11
16
|
def tag(x)
|
12
|
-
res = tag_sexpr(x
|
17
|
+
res = tag_sexpr(x)
|
13
18
|
res.should eq(x)
|
14
19
|
res
|
15
20
|
end
|
16
21
|
|
17
|
-
|
18
|
-
|
22
|
+
context 'when no tagging reference is provided' do
|
23
|
+
|
24
|
+
it 'tags with the default tagging module if set' do
|
25
|
+
tag([:lit]).should be_a(TaggingReference::Node)
|
26
|
+
tag([:or]).should be_a(TaggingReference::Node)
|
27
|
+
end
|
28
|
+
|
19
29
|
end
|
20
30
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
31
|
+
context 'when a tagging reference is provided' do
|
32
|
+
|
33
|
+
def tagging_reference
|
34
|
+
TaggingReference
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'tags a sexpr at first level' do
|
38
|
+
tag([:lit]).should be_a(TaggingReference::Lit)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'tags sexpr recursively' do
|
42
|
+
res = tag([:not, [:lit, true]])
|
43
|
+
res.should be_a(TaggingReference::Not)
|
44
|
+
res.last.should be_a(TaggingReference::Lit)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'tags with the default tagging module when no match' do
|
48
|
+
res = tag([:or]).should be_a(TaggingReference::Node)
|
49
|
+
end
|
25
50
|
end
|
26
51
|
|
27
52
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Sexpr
|
3
|
+
describe Processor, 'apply' do
|
4
|
+
|
5
|
+
let(:proc){ SimpleProcessor.new }
|
6
|
+
|
7
|
+
it 'dispatches to existing methods' do
|
8
|
+
ast = [:hello, "world"]
|
9
|
+
proc.apply(ast).should eq([:simple_hello, [:hello, "world"]])
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'calls on_missing when not found' do
|
13
|
+
ast = [:simple_missing, [:hello, "world"]]
|
14
|
+
proc.apply(ast).should eq([:simple_pass_missing, ast])
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'can be called from the inside' do
|
18
|
+
ast = [:apply, [:hello, "world"]]
|
19
|
+
proc.apply(ast).should eq([:simple_hello, [:hello, "world"]])
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'raises unexpected by default in on_missing' do
|
23
|
+
ast = [:nonono, "world"]
|
24
|
+
lambda{ proc.apply(ast) }.should raise_error(UnexpectedSexprError, /nonono/)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'raises an ArgumentError unless called on a sexpr' do
|
28
|
+
lambda{
|
29
|
+
proc.apply("world").should raise_error(ArgumentError, /world/)
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
data/spec/processor/test_call.rb
CHANGED
@@ -2,44 +2,45 @@ require 'spec_helper'
|
|
2
2
|
module Sexpr
|
3
3
|
describe Processor, 'call' do
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
context 'without preprocessors installed' do
|
6
|
+
let(:proc){ SimpleProcessor.new }
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
it 'returns the result of apply' do
|
9
|
+
ast = [:hello, "world"]
|
10
|
+
proc.call(ast).should eq([:simple_hello, [:hello, "world"]])
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
[:seen_missing, sexpr]
|
15
|
-
else
|
16
|
-
super
|
17
|
-
end
|
18
|
-
end
|
15
|
+
context "when preprocessors are installed" do
|
16
|
+
let(:proc){ SubPreprocessed.new }
|
19
17
|
|
18
|
+
it 'applies the preprocessors' do
|
19
|
+
ast = [:hello, "world"]
|
20
|
+
proc.call(ast).should eq([:preprocessed_hello, [:prefix_hello, "world"]])
|
20
21
|
end
|
21
|
-
}
|
22
|
-
let(:proc){ procclass.new }
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
it 'sets preprocessor results under state variables when required' do
|
24
|
+
ast = [:hello, "world"]
|
25
|
+
proc.call(ast)
|
26
|
+
proc.upcased.should eq("PREFIX_HELLO")
|
27
|
+
end
|
28
28
|
|
29
|
-
it 'calls on_missing when not found' do
|
30
|
-
ast = [:nosuchone, "world"]
|
31
|
-
proc.call(ast).should eq([:seen_missing, [:nosuchone, "world"]])
|
32
29
|
end
|
33
30
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
31
|
+
context 'when called on the class' do
|
32
|
+
|
33
|
+
it 'returns what an instance returns' do
|
34
|
+
expected = [:simple_hello, [:hello, "world"]]
|
35
|
+
SimpleProcessor.call([:hello, "world"]).should eq(expected)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'allows passing options' do
|
39
|
+
source = [:hello, "world"]
|
40
|
+
expected = [:do_hello, "world"]
|
41
|
+
Preprocessed::Prefix.call(source, :prefix => "do_").should eq(expected)
|
42
|
+
end
|
38
43
|
|
39
|
-
it 'raises an ArgumentError unless called on a sexpr' do
|
40
|
-
lambda{
|
41
|
-
proc.call("world").should raise_error(ArgumentError, /world/)
|
42
|
-
}
|
43
44
|
end
|
44
45
|
|
45
46
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Sexpr
|
3
|
+
describe Processor, "use" do
|
4
|
+
|
5
|
+
it 'installs the preprocessors properly' do
|
6
|
+
expected = []
|
7
|
+
Processor.preprocessors.should eq(expected)
|
8
|
+
|
9
|
+
expected << [Preprocessed::Prefix, {:prefix => "prefix_"}]
|
10
|
+
Preprocessed.preprocessors.should eq(expected)
|
11
|
+
|
12
|
+
expected << [ {:upcased => SubPreprocessed::Upcase}, nil ]
|
13
|
+
SubPreprocessed.preprocessors.should eq(expected)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'sets attribute readers for hashes' do
|
17
|
+
Preprocessed.new.should_not respond_to(:upcased)
|
18
|
+
SubPreprocessed.new.should respond_to(:upcased)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -7,27 +7,7 @@ $LOAD_PATH.unshift (root/"lib").to_s
|
|
7
7
|
require 'sexpr'
|
8
8
|
require (root/"examples/bool_expr/bool_expr").to_s
|
9
9
|
|
10
|
-
|
11
|
-
module Methods
|
12
|
-
end
|
13
|
-
|
14
|
-
def on_hello(rw, node)
|
15
|
-
raise unless rw.is_a?(FooProcessor)
|
16
|
-
[:foo_hello, yield(rw, node)]
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
20
|
-
class FooProcessor < Sexpr::Processor
|
21
|
-
helper FooHelper
|
22
|
-
end
|
23
|
-
|
24
|
-
class BarHelper < Sexpr::Processor::Helper
|
25
|
-
module Methods
|
26
|
-
end
|
27
|
-
end
|
28
|
-
class BarProcessor < FooProcessor
|
29
|
-
helper BarHelper
|
30
|
-
end
|
10
|
+
(Path.dir/:fixtures).glob("*.rb").each{|f| require f.without_extension}
|
31
11
|
|
32
12
|
def fixtures_path
|
33
13
|
Path.dir/"../examples/bool_expr"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sexpr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-25 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: epath
|
16
|
-
requirement: &
|
16
|
+
requirement: &81881430 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 0.0.1
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *81881430
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: citrus
|
27
|
-
requirement: &
|
27
|
+
requirement: &81881110 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '2.4'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *81881110
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rake
|
38
|
-
requirement: &
|
38
|
+
requirement: &81880830 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,21 +43,21 @@ dependencies:
|
|
43
43
|
version: 0.9.2
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *81880830
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rspec
|
49
|
-
requirement: &
|
49
|
+
requirement: &81880580 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 2.8
|
54
|
+
version: '2.8'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *81880580
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: wlang
|
60
|
-
requirement: &
|
60
|
+
requirement: &81880280 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,7 +65,7 @@ dependencies:
|
|
65
65
|
version: 0.10.2
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *81880280
|
69
69
|
description: Sexpr helps manipulating s-expressions in ruby.
|
70
70
|
email:
|
71
71
|
- blambeau@gmail.com
|
@@ -131,8 +131,9 @@ files:
|
|
131
131
|
- spec/rewriter/test_copy_and_apply.rb
|
132
132
|
- spec/processor/test_helper.rb
|
133
133
|
- spec/processor/test_sexpr_coercions.rb
|
134
|
-
- spec/processor/test_main_processor.rb
|
135
134
|
- spec/processor/test_build_helper_chain.rb
|
135
|
+
- spec/processor/test_use.rb
|
136
|
+
- spec/processor/test_apply.rb
|
136
137
|
- spec/processor/test_call.rb
|
137
138
|
- spec/processor/helper/test_call.rb
|
138
139
|
- spec/test_rewriter.rb
|
@@ -163,6 +164,10 @@ files:
|
|
163
164
|
- spec/node/test_sexpr_body.rb
|
164
165
|
- spec/node/test_sexpr_type.rb
|
165
166
|
- spec/test_readme_examples.rb
|
167
|
+
- spec/fixtures/preprocessed.rb
|
168
|
+
- spec/fixtures/simple_processor.rb
|
169
|
+
- spec/fixtures/bar.rb
|
170
|
+
- spec/fixtures/foo.rb
|
166
171
|
- tasks/debug_mail.rake
|
167
172
|
- tasks/yard.rake
|
168
173
|
- tasks/gem.rake
|
@@ -181,9 +186,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
181
186
|
- - ! '>='
|
182
187
|
- !ruby/object:Gem::Version
|
183
188
|
version: '0'
|
184
|
-
segments:
|
185
|
-
- 0
|
186
|
-
hash: -185808739
|
187
189
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
188
190
|
none: false
|
189
191
|
requirements:
|
@@ -215,8 +217,9 @@ test_files:
|
|
215
217
|
- spec/rewriter/test_copy_and_apply.rb
|
216
218
|
- spec/processor/test_helper.rb
|
217
219
|
- spec/processor/test_sexpr_coercions.rb
|
218
|
-
- spec/processor/test_main_processor.rb
|
219
220
|
- spec/processor/test_build_helper_chain.rb
|
221
|
+
- spec/processor/test_use.rb
|
222
|
+
- spec/processor/test_apply.rb
|
220
223
|
- spec/processor/test_call.rb
|
221
224
|
- spec/processor/helper/test_call.rb
|
222
225
|
- spec/test_rewriter.rb
|
@@ -247,3 +250,7 @@ test_files:
|
|
247
250
|
- spec/node/test_sexpr_body.rb
|
248
251
|
- spec/node/test_sexpr_type.rb
|
249
252
|
- spec/test_readme_examples.rb
|
253
|
+
- spec/fixtures/preprocessed.rb
|
254
|
+
- spec/fixtures/simple_processor.rb
|
255
|
+
- spec/fixtures/bar.rb
|
256
|
+
- spec/fixtures/foo.rb
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
module Sexpr
|
3
|
-
describe Processor, "main_processor" do
|
4
|
-
|
5
|
-
let(:procclass){ Class.new(Processor) }
|
6
|
-
|
7
|
-
it 'defaults to self' do
|
8
|
-
proc = procclass.new
|
9
|
-
proc.main_processor.should eq(proc)
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'may be specified through options' do
|
13
|
-
proc = procclass.new(:main_processor => :hello)
|
14
|
-
proc.main_processor.should eq(:hello)
|
15
|
-
end
|
16
|
-
|
17
|
-
end
|
18
|
-
end
|