mountain_berry_fields 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/.simplecov +12 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/Rakefile +30 -0
- data/Readme.md +184 -0
- data/Readme.md.mountain_berry_fields +197 -0
- data/bin/mountain_berry_fields +9 -0
- data/features/context_block.feature +73 -0
- data/features/cwd_is_dir_of_mbf_file.feature +16 -0
- data/features/rake_task.feature +46 -0
- data/features/setup_block.feature +36 -0
- data/features/step_definitions/steps.rb +46 -0
- data/features/support/env.rb +76 -0
- data/lib/mountain_berry_fields.rb +89 -0
- data/lib/mountain_berry_fields/command_line_interaction.rb +13 -0
- data/lib/mountain_berry_fields/evaluator.rb +90 -0
- data/lib/mountain_berry_fields/parser.rb +101 -0
- data/lib/mountain_berry_fields/rake_task.rb +12 -0
- data/lib/mountain_berry_fields/test.rb +88 -0
- data/lib/mountain_berry_fields/test/always_fail.rb +21 -0
- data/lib/mountain_berry_fields/test/always_pass.rb +19 -0
- data/lib/mountain_berry_fields/version.rb +3 -0
- data/mountain_berry_fields.gemspec +29 -0
- data/readme_helper.rb +205 -0
- data/spec/command_line_interaction_spec.rb +16 -0
- data/spec/evaluator_spec.rb +170 -0
- data/spec/mock_substitutability_spec.rb +25 -0
- data/spec/mountain_berry_fields_spec.rb +147 -0
- data/spec/parser_spec.rb +139 -0
- data/spec/ruby_syntax_checker_spec.rb +27 -0
- data/spec/spec_helper.rb +104 -0
- data/spec/test/always_fail_spec.rb +25 -0
- data/spec/test/always_pass_spec.rb +15 -0
- data/spec/test/strategy_spec.rb +48 -0
- data/spec/test/test_spec.rb +22 -0
- metadata +209 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MountainBerryFields::CommandLineInteraction do
|
4
|
+
let(:interaction) { described_class.new }
|
5
|
+
let(:stderr) { interaction.stderr.string }
|
6
|
+
|
7
|
+
it 'implements the interaction interface' do
|
8
|
+
Mock::Interaction.should substitute_for MountainBerryFields::CommandLineInteraction, subset: true
|
9
|
+
end
|
10
|
+
|
11
|
+
specify '#declare_failure(message) writes messages to stderr, with newlines' do
|
12
|
+
interaction.declare_failure "failure one"
|
13
|
+
interaction.declare_failure "failure two"
|
14
|
+
stderr.should == "failure one\nfailure two\n"
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MountainBerryFields::Evaluator do
|
4
|
+
it 'implements the evaluator interface' do
|
5
|
+
Mock::Evaluator.should substitute_for described_class, subset: true
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:to_evaluate) { '' }
|
9
|
+
let(:evaluator) { described_class.new to_evaluate }
|
10
|
+
|
11
|
+
it 'has a document which is initialized to empty string and memoized' do
|
12
|
+
evaluator = described_class.new ''
|
13
|
+
evaluator.document.should == ''
|
14
|
+
evaluator.document << 'abc'
|
15
|
+
evaluator.document.should == 'abc'
|
16
|
+
end
|
17
|
+
|
18
|
+
def should_evaluate
|
19
|
+
evaluator = described_class.new('def meth;end')
|
20
|
+
evaluator.should_not respond_to :meth
|
21
|
+
yield evaluator
|
22
|
+
evaluator.should respond_to :meth
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'ensures evaluation when asked for its document' do
|
26
|
+
should_evaluate { |evaluator| evaluator.document }
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'ensures evaluation when asked if tests pass' do
|
30
|
+
should_evaluate { |evaluator| evaluator.tests_pass? }
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'evaluation' do
|
34
|
+
it 'instance evals the string only once' do
|
35
|
+
evaluator = described_class.new('def meth;end; document << "abc"')
|
36
|
+
evaluator.evaluate
|
37
|
+
evaluator.evaluate
|
38
|
+
evaluator.document.should == 'abc'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
describe '#tests_pass?' do
|
44
|
+
test_class = MountainBerryFields::Test
|
45
|
+
|
46
|
+
it 'evaluates the text if not evaluated' do
|
47
|
+
should_evaluate { |evaluator| evaluator.tests_pass? }
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns true if all its tests pass' do
|
51
|
+
evaluator = described_class.new ''
|
52
|
+
evaluator.test('Passing test', with: :always_pass) {''}
|
53
|
+
evaluator.tests_pass?.should == true
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'tracks the failure name and message, if any of its tests fail' do
|
57
|
+
evaluator = described_class.new ''
|
58
|
+
evaluator.test('Failbert', with: :always_fail) {}
|
59
|
+
evaluator.tests_pass?.should == false
|
60
|
+
evaluator.failure_name.should == 'Failbert'
|
61
|
+
evaluator.failure_message.should == MountainBerryFields::Test::Strategy.for(:always_fail).new('').failure_message
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'visible and invisble commands' do
|
66
|
+
specify '#visible_commands is an array of commands whose output should be displayed' do
|
67
|
+
described_class.visible_commands.should be_a_kind_of Array
|
68
|
+
end
|
69
|
+
|
70
|
+
specify '#invisible_commands is an array of commands whose output should be omitted from the final document' do
|
71
|
+
described_class.invisible_commands.should be_a_kind_of Array
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
describe '#test' do
|
77
|
+
it 'is visible' do
|
78
|
+
described_class.visible_commands.should include :test
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'adds a test with the given name, and options' do
|
82
|
+
options = { code: 'some code', with: :always_fail }
|
83
|
+
evaluator = described_class.new ''
|
84
|
+
evaluator.tests.size.should == 0
|
85
|
+
evaluator.test('some name', options) { '' }
|
86
|
+
evaluator.tests.size.should == 1
|
87
|
+
evaluator.tests.first.name.should == 'some name'
|
88
|
+
evaluator.tests.first.strategy.should == :always_fail
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'immediately evaluates the test' do
|
92
|
+
$abc = ''
|
93
|
+
evaluator.test 'whatev', with: :always_pass do
|
94
|
+
'$abc = "abc"'
|
95
|
+
end
|
96
|
+
$abc.should == 'abc'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
describe '#setup' do
|
102
|
+
it 'is invisible' do
|
103
|
+
described_class.invisible_commands.should include :setup
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'is prepended before each test added after it' do
|
107
|
+
evaluator.test('name', with: :always_pass) { "test1\n" }
|
108
|
+
evaluator.setup { "setup\n" }
|
109
|
+
evaluator.test('name', with: :always_pass) { "test2\n" }
|
110
|
+
evaluator.test('name', with: :always_pass) { "test3\n" }
|
111
|
+
evaluator.tests[0].code.should == "test1\n"
|
112
|
+
evaluator.tests[1].code.should == "setup\ntest2\n"
|
113
|
+
evaluator.tests[2].code.should == "setup\ntest3\n"
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'appends to the setup code if invoked multiple times' do
|
117
|
+
evaluator.setup { "setup1\n" }
|
118
|
+
evaluator.setup { "setup2\n" }
|
119
|
+
evaluator.test('name', with: :always_pass) { "test1\n" }
|
120
|
+
evaluator.tests.first.code.should == "setup1\nsetup2\ntest1\n"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
describe '#context' do
|
126
|
+
let(:context_name) { 'some context name' }
|
127
|
+
let(:test_name) { 'some test name' }
|
128
|
+
|
129
|
+
it 'is invisible' do
|
130
|
+
described_class.invisible_commands.should include :context
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'must have at least one __CODE__ section in it' do
|
134
|
+
expect {
|
135
|
+
evaluator.context(context_name) { 'no code section' }
|
136
|
+
}.to raise_error ArgumentError, /#{context_name}.*__CODE__/
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'replaces all __CODE__ section with the test using it' do
|
140
|
+
evaluator.context(context_name) { 'a __CODE__ c __CODE__' }
|
141
|
+
evaluator.test(test_name, with: :always_pass, context: context_name) { 'b' }
|
142
|
+
evaluator.tests.first.code.should == 'a b c b'
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'raises an error when a test references a nonexistent context' do
|
146
|
+
evaluator.context(context_name) { '__CODE__' }
|
147
|
+
expect {
|
148
|
+
evaluator.test(test_name, with: :always_pass, context: context_name.reverse) {''}
|
149
|
+
}.to raise_error NameError, /#{context_name.reverse}.*#{context_name}/
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'is applied after setup' do
|
153
|
+
evaluator.setup { 'a' }
|
154
|
+
evaluator.context(context_name) { ' b __CODE__' }
|
155
|
+
evaluator.test(test_name, context: context_name, with: :always_pass) { 'c' }
|
156
|
+
evaluator.tests.first.code.should == 'a b c'
|
157
|
+
end
|
158
|
+
|
159
|
+
let(:context_name1) { 'context name 1' }
|
160
|
+
let(:context_name2) { 'context name 2' }
|
161
|
+
specify 'contexts can have contexts of their own' do
|
162
|
+
evaluator.context(context_name1) { 'a __CODE__ b' }
|
163
|
+
evaluator.context(context_name2, context: context_name1) { 'c __CODE__ d' }
|
164
|
+
evaluator.test(test_name, context: context_name1, with: :always_pass) { 'e' }
|
165
|
+
evaluator.test(test_name, context: context_name2, with: :always_pass) { 'f' }
|
166
|
+
evaluator.tests[0].code.should == 'a e b'
|
167
|
+
evaluator.tests[1].code.should == 'a c f d b'
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mock::File do
|
4
|
+
it 'is substitutable for ::File' do
|
5
|
+
Mock::File.should substitute_for ::File, subset: true
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe Mock::Dir do
|
10
|
+
it 'is substitutable for ::Dir' do
|
11
|
+
Mock::Dir.should substitute_for Dir, subset: true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe Mock::Process::Status do
|
16
|
+
it 'is substitutable for ::Process::Status' do
|
17
|
+
Mock::Process::Status.should substitute_for ::Process::Status, subset: true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe Mock::Open3 do
|
22
|
+
it 'is substitutable for ::Open3' do
|
23
|
+
Mock::Open3.should substitute_for ::Open3, subset: true
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MountainBerryFields do
|
4
|
+
let(:dir_class) { mbf.dir_class }
|
5
|
+
let(:file_class) { mbf.file_class }
|
6
|
+
let(:stderr) { mbf.stderr.string }
|
7
|
+
let(:interaction) { mbf.interaction }
|
8
|
+
let(:evaluator) { mbf.evaluator }
|
9
|
+
let(:parser) { mbf.parser }
|
10
|
+
|
11
|
+
shared_examples 'a failure' do
|
12
|
+
it 'returns false' do
|
13
|
+
mbf.execute.should == false
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'does not write any files' do
|
17
|
+
file_class.should_not have_been_told_to :write
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
context 'when no input file is provided' do
|
23
|
+
nonexistence_message = 'Please provide an input file'
|
24
|
+
let(:mbf) { described_class.new [] }
|
25
|
+
|
26
|
+
it_behaves_like 'a failure'
|
27
|
+
|
28
|
+
it "declares the error '#{nonexistence_message}'" do
|
29
|
+
mbf.execute
|
30
|
+
interaction.should have_been_told_to(:declare_failure).with(nonexistence_message)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
context 'when the input file does not exist' do
|
36
|
+
nonexistent_filename = '/some/bullshit/file.mountain_berry_fields.md'.freeze
|
37
|
+
nonexistence_message = "#{nonexistent_filename.inspect} does not exist.".freeze
|
38
|
+
|
39
|
+
let(:mbf) { described_class.new [nonexistent_filename] }
|
40
|
+
before { file_class.will_exist? false }
|
41
|
+
|
42
|
+
it_behaves_like 'a failure'
|
43
|
+
|
44
|
+
it "declares the error '#{nonexistent_filename}'" do
|
45
|
+
mbf.execute
|
46
|
+
file_class.should have_been_asked_for_its(:exist?).with(nonexistent_filename)
|
47
|
+
interaction.should have_been_told_to(:declare_failure).with(nonexistence_message)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
context 'when the input file does not match /\.mountain_berry_fields\b/' do
|
53
|
+
invalid_filename = "invalid_filename.md"
|
54
|
+
invalid_filename_message = "#{invalid_filename.inspect} does not match /\\.mountain_berry_fields\\b/"
|
55
|
+
let(:mbf) { described_class.new [invalid_filename] }
|
56
|
+
|
57
|
+
it "declares the error '#{invalid_filename_message}'" do
|
58
|
+
mbf.execute
|
59
|
+
interaction.should have_been_told_to(:declare_failure).with(invalid_filename_message)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'when unsuccessfully parsing a file' do
|
64
|
+
let(:input_filename) { 'some_invalid_file.mountain_berry_fields.md' }
|
65
|
+
let(:mbf) { described_class.new [input_filename] }
|
66
|
+
before { parser.will_parse StandardError.new "some error message" }
|
67
|
+
|
68
|
+
it_behaves_like 'a failure'
|
69
|
+
|
70
|
+
it 'writes the exception class and message as the error' do
|
71
|
+
mbf.execute
|
72
|
+
interaction.should have_been_told_to(:declare_failure).with("StandardError some error message")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'when successfully parsing a file' do
|
77
|
+
let(:input_filepath) { '/a/b/c' }
|
78
|
+
let(:input_filename) { input_filepath + '/some_valid_file.mountain_berry_fields.md' }
|
79
|
+
let(:output_filename) { input_filepath + '/some_valid_file.md' }
|
80
|
+
let(:mbf) { described_class.new [input_filename] }
|
81
|
+
let(:file_body) { 'SOME FILE BODY' }
|
82
|
+
let(:parsed_body) { 'PARSED BODY' }
|
83
|
+
let(:document) { 'EVALUATED DOCUMENT' }
|
84
|
+
|
85
|
+
before { file_class.will_read file_body }
|
86
|
+
before { parser.will_parse parsed_body }
|
87
|
+
|
88
|
+
it 'declares no errors' do
|
89
|
+
mbf.execute
|
90
|
+
interaction.should_not have_been_told_to :declare_failure
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'passes the file contents to the parser' do
|
94
|
+
visible_commands = mbf.evaluator_class.visible_commands
|
95
|
+
invisible_commands = mbf.evaluator_class.invisible_commands
|
96
|
+
mbf.execute
|
97
|
+
file_class.should have_been_told_to(:read).with(/#{input_filename}$/)
|
98
|
+
parser.should have_been_initialized_with file_body, visible: visible_commands, invisible: invisible_commands
|
99
|
+
end
|
100
|
+
|
101
|
+
it "evaluates the results of the parsing, in the input file's directory" do
|
102
|
+
dir_class.will_chdir false
|
103
|
+
mbf.execute
|
104
|
+
dir_class.should have_been_told_to(:chdir).with(input_filepath) { |block|
|
105
|
+
block.before { evaluator.should_not have_been_asked_if :tests_pass? }
|
106
|
+
block.after { evaluator.should have_been_asked_if :tests_pass? }
|
107
|
+
}
|
108
|
+
evaluator.should have_been_initialized_with parsed_body
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
context 'when the tests pass' do
|
113
|
+
before { evaluator.will_tests_pass? true }
|
114
|
+
before { evaluator.will_have_document document }
|
115
|
+
|
116
|
+
it 'returns true' do
|
117
|
+
mbf.execute.should == true
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'writes the interpreted file to the new filename (the same name, but with mountain_berry_fields segment removed)' do
|
121
|
+
mbf.execute
|
122
|
+
file_class.should have_been_told_to(:write).with(output_filename, document)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'when the tests fail' do
|
127
|
+
before { evaluator.will_tests_pass? false }
|
128
|
+
it_behaves_like 'a failure'
|
129
|
+
|
130
|
+
it "declares the failure with the evaluator's failure's name and message" do
|
131
|
+
evaluator.will_have_failure_name "sir"
|
132
|
+
evaluator.will_have_failure_message "failsalot"
|
133
|
+
mbf.execute
|
134
|
+
interaction.should have_been_told_to(:declare_failure).with("FAILURE: sir\nfailsalot")
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'when evaluation raises an exception' do
|
139
|
+
before { evaluator.will_tests_pass? StandardError.new('blah') }
|
140
|
+
it_behaves_like 'a failure'
|
141
|
+
it 'writes the exception class and message as the error' do
|
142
|
+
mbf.execute
|
143
|
+
interaction.should have_been_told_to(:declare_failure).with("StandardError blah")
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
data/spec/parser_spec.rb
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MountainBerryFields::Parser do
|
4
|
+
let :evaluator_class do
|
5
|
+
Class.new do
|
6
|
+
attr_reader :document, :visible_saw, :invisible_saw
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@document = ''
|
10
|
+
@visible_saw = []
|
11
|
+
@invisible_saw = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def visible
|
15
|
+
@visible_saw << yield
|
16
|
+
'visible'
|
17
|
+
end
|
18
|
+
|
19
|
+
def invisible
|
20
|
+
@invisible_saw << yield
|
21
|
+
'invisible'
|
22
|
+
end
|
23
|
+
|
24
|
+
def record_args(*args)
|
25
|
+
@recorded_args = args
|
26
|
+
end
|
27
|
+
|
28
|
+
def recorded_args
|
29
|
+
@recorded_args
|
30
|
+
end
|
31
|
+
|
32
|
+
def inspect
|
33
|
+
"#<evaluator_class>"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_reader :evaluator
|
39
|
+
|
40
|
+
def visible_in(code)
|
41
|
+
parsed code
|
42
|
+
evaluator.visible_saw
|
43
|
+
end
|
44
|
+
|
45
|
+
def invisible_in(code)
|
46
|
+
parsed code
|
47
|
+
evaluator.invisible_saw
|
48
|
+
end
|
49
|
+
|
50
|
+
def recorded_args(code)
|
51
|
+
parsed code
|
52
|
+
evaluator.recorded_args
|
53
|
+
end
|
54
|
+
|
55
|
+
def parsed(text)
|
56
|
+
program = described_class.new(text, visible: [:visible], invisible: [:invisible]).parse
|
57
|
+
@evaluator = evaluator_class.new
|
58
|
+
@evaluator.instance_eval program
|
59
|
+
@evaluator.document
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'parses normal erb code' do
|
63
|
+
parsed("a\n<% if true %>\ndo shit\n<% end %>b").should == "a\ndo shit\nb\n"
|
64
|
+
parsed("a\n<% if false %>do shit<% end %>b").should == "a\nb\n"
|
65
|
+
parsed("a<% if true %>b<% end %>c").should == "abc\n"
|
66
|
+
parsed("a<%= 1 + 2 %>b").should == "a3b\n"
|
67
|
+
parsed("a<%# comment %>b").should == "ab\n"
|
68
|
+
parsed("a<%% whatev %>b").should == "a<% whatev %>b\n"
|
69
|
+
parsed("a<%%= whatev %>b").should == "a<%= whatev %>b\n"
|
70
|
+
parsed("a<% if 'I' %>b<% end %>c").should == "abc\n"
|
71
|
+
recorded_args("a<% record_args 'I' %>").should == ['I']
|
72
|
+
recorded_args("a<%= record_args 'I' %>").should == ['I']
|
73
|
+
end
|
74
|
+
|
75
|
+
specify 'results always end with a newline' do
|
76
|
+
parsed("abc").should == "abc\n"
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'visible methods' do
|
80
|
+
specify 'are provided in a list to the constructor and converted to strings' do
|
81
|
+
described_class.new('', visible: [:a]).visible_commands.should == ['a']
|
82
|
+
end
|
83
|
+
|
84
|
+
specify 'default to an empty array' do
|
85
|
+
described_class.new('').visible_commands.should == []
|
86
|
+
end
|
87
|
+
|
88
|
+
specify 'show up in the document when evaluated' do
|
89
|
+
parsed("a<% visible do %>b<% end %>c").should == "abc\n"
|
90
|
+
end
|
91
|
+
|
92
|
+
specify 'are returned when the block is invoked' do
|
93
|
+
visible_in("a<% visible do %>b<% end %>c").should == ['b']
|
94
|
+
end
|
95
|
+
|
96
|
+
specify "support basic nesting (can't do complex nesting without editing parse trees -- not a big deal, these are things that even erubis can't do)" do
|
97
|
+
visible_in("a<%visible {%>b<%visible {%>c<% } %>d<% } %>e").should == ['c', 'bd']
|
98
|
+
visible_in("a<%visible {%>b<%if false %>c<% end %>d<% } %>e").should == ['bd']
|
99
|
+
visible_in("<%# visible %>").should == []
|
100
|
+
visible_in('<% visible do %>\'a\'\\<% end %>').should == ['\'a\'\\']
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe 'invisible methods' do
|
105
|
+
specify 'are provided in a list to the constructor and converted to strings' do
|
106
|
+
described_class.new('', invisible: [:a]).invisible_commands.should == ['a']
|
107
|
+
end
|
108
|
+
|
109
|
+
specify 'default to an empty array' do
|
110
|
+
described_class.new('').invisible_commands.should == []
|
111
|
+
end
|
112
|
+
|
113
|
+
specify 'do not show up in the document when evaluated' do
|
114
|
+
parsed("a<% invisible do %>b<% end %>c").should == "ac\n"
|
115
|
+
end
|
116
|
+
|
117
|
+
specify 'are returned when the block is invoked' do
|
118
|
+
invisible_in("a<% invisible do %>b<% end %>c").should == ['b']
|
119
|
+
end
|
120
|
+
|
121
|
+
specify "support basic nesting (can't do complex nesting without editing parse trees -- not a big deal, these are things that even erubis can't do)" do
|
122
|
+
invisible_in("a<%invisible {%>b<%invisible {%>c<% } %>d<% } %>e").should == ['c', 'bd']
|
123
|
+
invisible_in("a<%invisible {%>b<%if false %>c<% end %>d<% } %>e").should == ['bd']
|
124
|
+
invisible_in("<%# invisible %>").should == []
|
125
|
+
invisible_in('<% invisible do %>\'a\'\\<% end %>').should == ['\'a\'\\']
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Unfortunately, this problem is in Erubis.
|
130
|
+
# It might be possible to fix it in the subclass,
|
131
|
+
# but that seems like a lot of work for an incredibly rare use case
|
132
|
+
# so just going to leave this pending for now.
|
133
|
+
#
|
134
|
+
# Erubis::Eruby.new('<% a = "<% b %>"; a * 2 %>').src # => "_buf = ''; a = \"<% b ; _buf << '\"; a * 2 %>';\n_buf.to_s\n"
|
135
|
+
xit 'ignores erb tags inside erb blocks' do
|
136
|
+
parse("a<% s='<% visible { %>b<% } %>' %>c").should == "ac\n"
|
137
|
+
parsed("a<% s='<% invisible { %>b<% } %>' %>c").should == "ac\n"
|
138
|
+
end
|
139
|
+
end
|