mountain_berry_fields 1.0.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/.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
|