mountain_berry_fields 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/.gitignore +19 -0
  2. data/.simplecov +12 -0
  3. data/Gemfile +2 -0
  4. data/LICENSE +22 -0
  5. data/Rakefile +30 -0
  6. data/Readme.md +184 -0
  7. data/Readme.md.mountain_berry_fields +197 -0
  8. data/bin/mountain_berry_fields +9 -0
  9. data/features/context_block.feature +73 -0
  10. data/features/cwd_is_dir_of_mbf_file.feature +16 -0
  11. data/features/rake_task.feature +46 -0
  12. data/features/setup_block.feature +36 -0
  13. data/features/step_definitions/steps.rb +46 -0
  14. data/features/support/env.rb +76 -0
  15. data/lib/mountain_berry_fields.rb +89 -0
  16. data/lib/mountain_berry_fields/command_line_interaction.rb +13 -0
  17. data/lib/mountain_berry_fields/evaluator.rb +90 -0
  18. data/lib/mountain_berry_fields/parser.rb +101 -0
  19. data/lib/mountain_berry_fields/rake_task.rb +12 -0
  20. data/lib/mountain_berry_fields/test.rb +88 -0
  21. data/lib/mountain_berry_fields/test/always_fail.rb +21 -0
  22. data/lib/mountain_berry_fields/test/always_pass.rb +19 -0
  23. data/lib/mountain_berry_fields/version.rb +3 -0
  24. data/mountain_berry_fields.gemspec +29 -0
  25. data/readme_helper.rb +205 -0
  26. data/spec/command_line_interaction_spec.rb +16 -0
  27. data/spec/evaluator_spec.rb +170 -0
  28. data/spec/mock_substitutability_spec.rb +25 -0
  29. data/spec/mountain_berry_fields_spec.rb +147 -0
  30. data/spec/parser_spec.rb +139 -0
  31. data/spec/ruby_syntax_checker_spec.rb +27 -0
  32. data/spec/spec_helper.rb +104 -0
  33. data/spec/test/always_fail_spec.rb +25 -0
  34. data/spec/test/always_pass_spec.rb +15 -0
  35. data/spec/test/strategy_spec.rb +48 -0
  36. data/spec/test/test_spec.rb +22 -0
  37. metadata +209 -0
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ features/proving_grounds
19
+ .DS_Store
@@ -0,0 +1,12 @@
1
+ SimpleCov.start do
2
+ add_filter '/spec/'
3
+ add_filter '/features/'
4
+
5
+ # this gets acceptance tested, not unit tested
6
+ add_filter 'formatter.rb'
7
+
8
+ # don't look at coverage of plugins, let them test themselves
9
+ add_filter do |source_file|
10
+ !source_file.filename[File.dirname(__FILE__)+'/']
11
+ end
12
+ end
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Josh Cheek
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
3
+
4
+ task :rspec do
5
+ require 'rspec'
6
+ Dir.glob("spec/**/*_spec.rb").each { |filename| require File.expand_path filename }
7
+ RSpec::Core::Runner.run []
8
+ end
9
+
10
+ require 'cucumber/rake/task'
11
+ default_cucumber_opts = "features --format pretty --tags ~@not-implemented"
12
+ Cucumber::Rake::Task.new(:cucumber) { |t| t.cucumber_opts = default_cucumber_opts + " --tags ~@wip" }
13
+ Cucumber::Rake::Task.new('cucumber:wip') { |t| t.cucumber_opts = default_cucumber_opts + " --tags @wip" }
14
+
15
+
16
+ task rspec_must_be_100_percent: :rspec do
17
+ percent = SimpleCov.result.covered_percent
18
+ unless percent == 100
19
+ SimpleCov.result.format!
20
+ fail "\e[31mYo, dawg some of your shit isn't getting tested, only %0.2f%%\e[0m" % percent
21
+ end
22
+ end
23
+
24
+
25
+ require 'mountain_berry_fields/rake_task'
26
+ MountainBerryFields::RakeTask.new(:generate_readme, 'Readme.md.mountain_berry_fields')
27
+
28
+ task default: [:rspec_must_be_100_percent, :cucumber, :generate_readme]
29
+
30
+
@@ -0,0 +1,184 @@
1
+ # MountainBerryFields
2
+
3
+ Tests code in readme files, generates the readme if they are successful.
4
+
5
+ ## Usage
6
+
7
+ When you have a file with embedded code samples, rename it to include a .mountain_berry_fields suffix.
8
+ Then wrap test statements around the code samples. I've written two testing strategies: rspec and magic_comments.
9
+ You can create your own without much effort.
10
+
11
+
12
+ ### Code samples with magic comments
13
+
14
+ You will need to
15
+ `$ gem install mountain_berry_fields-magic_comments`
16
+ for this to work.
17
+
18
+ The file `Readme.mountain_berry_fields.md`
19
+
20
+ # MyLibName
21
+
22
+ <% test 'an example', with: :magic_comments do %>
23
+ MyLibName.new('some data').result # => "some cool result"
24
+ <% end %>
25
+
26
+ Run `$ mountain_berry_fields Readme.mountain_berry_fields.md` and it will generate `Readme.md`
27
+
28
+ # MyLibName
29
+
30
+ MyLibName.new('some data').result # => "some cool result"
31
+
32
+ If at some point, you change your lib to not do that cool thing, then it will not generate the file. Instead it will give you an error message:
33
+
34
+ FAILURE: an example
35
+ Expected: MyLibName.new('some data').result # => "some cool result"
36
+ Actual: MyLibName.new('some data').result # => "some unexpected result"
37
+
38
+ Now you can be confident that your code is still legit.
39
+
40
+ Realworld [example](https://github.com/JoshCheek/deject/blob/8eb0d92949318cf4ef87c2b1a2070328024b0196/Readme.md.mountain_berry_fields#L40-48).
41
+
42
+ ### Code samples with RSpec
43
+
44
+ You will need to
45
+ `$ gem install mountain_berry_fields-rspec`
46
+ for this to work.
47
+
48
+ The file `Readme.mountain_berry_fields.md`
49
+
50
+ # MyLibName
51
+
52
+ <% test 'an example', with: :rspec do %>
53
+ describe MyLibName do
54
+ it 'does what I made it do' do
55
+ described_class.new('some data').result.should == 'some cool result'
56
+ end
57
+ end
58
+ <% end %>
59
+
60
+ Run `$ mountain_berry_fields Readme.mountain_berry_fields.md` to generate `Readme.md`
61
+
62
+ # MyLibName
63
+
64
+ describe MyLibName do
65
+ it 'does what I made it do' do
66
+ described_class.new('some data').result.should == 'some cool result'
67
+ end
68
+ end
69
+
70
+ And an rspec error:
71
+
72
+ FAILURE: an example
73
+ MyLibName does what I made it do:
74
+ expected: "some cool result"
75
+ got: "some unexpected result" (using ==)
76
+
77
+ backtrace:
78
+ /spec.rb:8:in `block (2 levels) in <top (required)>'
79
+
80
+ Realworld [example](https://github.com/JoshCheek/surrogate/blob/b7ad4d3cd5ce2e3b8bf44c3743436e4d614b1991/Readme.md.mountain_berry_fields#L254-258).
81
+
82
+ ### Setup blocks
83
+
84
+ You may need to do something to setup the environment for the tests (e.g. load the lib your examples are using)
85
+ Do that with a setup block:
86
+
87
+ <% setup do %>
88
+ $LOAD_PATH.unshift File.expand_path '../lib', __FILE__
89
+ require 'my_lib_name'
90
+ <% end %>
91
+
92
+ This will not show up anywhere in the generated file. It will be prepended before each code sample when running tests.
93
+
94
+ Realworld [example](https://github.com/JoshCheek/deject/blob/8eb0d92949318cf4ef87c2b1a2070328024b0196/Readme.md.mountain_berry_fields#L22-25).
95
+
96
+ ### Context blocks
97
+
98
+ Some examples may need to be executed within a context. Use a context block for that.
99
+ Use the `__CODE__` macro to indicate where the code should go relative to this context.
100
+
101
+ <% context 'a user named Carlita' do %>
102
+ user = Struct.new(:name).new 'Carlita'
103
+ __CODE__
104
+ <% end %>
105
+
106
+ <% test 'users have a name', context: 'a user named Carlita', with: :magic_comments do %>
107
+ user.name # => "Carlita"
108
+ <% end %>
109
+
110
+ Context blocks can, themselves, be rendered into a context `<% context 'current', context: "my context's context" do %>`
111
+
112
+ Realworld [example](https://github.com/JoshCheek/surrogate/blob/b7ad4d3cd5ce2e3b8bf44c3743436e4d614b1991/Readme.md.mountain_berry_fields#L237-258).
113
+
114
+ ### Rake Task
115
+
116
+ If you want to add this as part of your build, there is a rake task:
117
+
118
+ ```ruby
119
+ require 'mountain_berry_fields/rake_task'
120
+ MountainBerryFields::RakeTask.new(:mbf, 'Readme.mountain_berry_fields.md')
121
+ ```
122
+
123
+ which will allow you to say `$ rake mbf`. You could then add it to your default task with
124
+ `task default: :mbf`, or have whatever task runs your tests just execute it at the end.
125
+
126
+ Realworld [example](https://github.com/JoshCheek/surrogate/blob/b7ad4d3cd5ce2e3b8bf44c3743436e4d614b1991/Rakefile#L13-17).
127
+
128
+ ### Creating your own test strategy
129
+
130
+ I've written the magic_comments and rspec strategies. You can write your own that do
131
+ whatever interesting thing you've thought of.
132
+
133
+ If you want it to be a gem, then the strategy needs to be in the file
134
+ `mountain_berry_fields/test/your_strategy.rb`. Mountain Berry Fields
135
+ will automatically load files at these paths. If your strategy is not a gem,
136
+ then it is up to you to ensure the code defining the strategy is loaded.
137
+
138
+ Any strategy can be made accessible to the .mountain_berry_fields file like this:
139
+ `MountainBerryFields::Test::Strategy.register :your_strategy, YourStrategy`
140
+ And then accessed by `<% test 'testname', with: :your_strategy do %>`
141
+
142
+ Strategies will be initialized with the code to test, and are expected to
143
+ implement `#pass?` which returns a boolean of whether the code passes according
144
+ to that strategy, and `#failure_message` which will used to describe why the spec
145
+ failed to users.
146
+
147
+ Realworld gem [example](https://github.com/JoshCheek/mountain_berry_fields-rspec/blob/cc6364ad106a7c65822542709bc5676bfb0b2c07/lib/mountain_berry_fields/test/rspec.rb).
148
+ Realworld non-gem [example](https://github.com/JoshCheek/mountain_berry_fields/blob/be751536c8b0f94c84b09167fa83616b94b13b12/readme_helper.rb).
149
+
150
+ ### About the name
151
+
152
+ I am often asked why I picked this name. I make things like this for me, because I have decided that they have value.
153
+ I felt the need to remind myself of that so I chose a name that no one would realisitcally choose,
154
+ to remind myself of the fact that no one could tell me I couldn't choose it.
155
+
156
+ The phrase "Mountain berry fields" is a lyric in a [song](http://www.myspace.com/joyelectric/music/songs/birds-will-sing-forever-christian-songs-album-version-34576758) that makes me happy.
157
+
158
+ If it bothers you: `$ alias mbf=mountain_berry_fields`
159
+
160
+ ## TODO
161
+ * set it up on Travis
162
+
163
+ ## Features to add for v2
164
+
165
+ Note that my use cases are to be able to test Deject and Surrogate,
166
+ which this currently does quite nicely. As a result, I have no imminent
167
+ need for any of these features, and so they are not a priority for me.
168
+ If you have a need for them (or for other features), let me know and that
169
+ will cause it to be a much higher priority for me. Alternatively,
170
+ pull requests that add them, fix bugs, or generally make it better,
171
+ are more than welcome.
172
+
173
+ * contexts should be lazy (can define context after a block that uses it)
174
+ * should be able to pass options to the initializer
175
+ * enable the test strategy to decide what should be returned
176
+ * support for multiple input files
177
+ * FLAGS:
178
+ * * -o set up input files so they don't need a .mountain_berry_fields in their name (output filename is provided, so input filename needs no naming conventions)
179
+ * * -s list all known test strategies
180
+ * * -v version
181
+ * * -c check syntax (no output, thus also no input filename restrictions)
182
+ * * -e flag for outputting erb (e.g. when it gives weird ass _buf error)
183
+ * * -h to display this menu
184
+ * * ?? to display the code that was passed to the test, along with the failure
@@ -0,0 +1,197 @@
1
+ <% load "readme_helper.rb" %>
2
+ # MountainBerryFields
3
+
4
+ Tests code in readme files, generates the readme if they are successful.
5
+
6
+ ## Usage
7
+
8
+ When you have a file with embedded code samples, rename it to include a .mountain_berry_fields suffix.
9
+ Then wrap test statements around the code samples. I've written two testing strategies: rspec and magic_comments.
10
+ You can create your own without much effort.
11
+
12
+
13
+ ### Code samples with magic comments
14
+
15
+ You will need to
16
+ `<% test('dep magic_comments', with: :install_dep) { %>$ gem install mountain_berry_fields-magic_comments<% } %>`
17
+ for this to work.
18
+
19
+ <% test 'show magic comments', with: :mbf_example do %>
20
+ The file `Readme.mountain_berry_fields.md`
21
+
22
+ # MyLibName
23
+
24
+ <%% test 'an example', with: :magic_comments do %>
25
+ MyLibName.new('some data').result # => "some cool result"
26
+ <%% end %>
27
+
28
+ Run `$ mountain_berry_fields Readme.mountain_berry_fields.md` and it will generate `Readme.md`
29
+
30
+ # MyLibName
31
+
32
+ MyLibName.new('some data').result # => "some cool result"
33
+
34
+ If at some point, you change your lib to not do that cool thing, then it will not generate the file. Instead it will give you an error message:
35
+
36
+ FAILURE: an example
37
+ Expected: MyLibName.new('some data').result # => "some cool result"
38
+ Actual: MyLibName.new('some data').result # => "some unexpected result"
39
+ <% end %>
40
+
41
+ Now you can be confident that your code is still legit.
42
+
43
+ Realworld [example](https://github.com/JoshCheek/deject/blob/8eb0d92949318cf4ef87c2b1a2070328024b0196/Readme.md.mountain_berry_fields#L40-49).
44
+
45
+ ### Code samples with RSpec
46
+
47
+ You will need to
48
+ `<% test('dep rspec', with: :install_dep) { %>$ gem install mountain_berry_fields-rspec<% } %>`
49
+ for this to work.
50
+
51
+ <% test 'show rspec', with: :mbf_example do %>
52
+ The file `Readme.mountain_berry_fields.md`
53
+
54
+ # MyLibName
55
+
56
+ <%% test 'an example', with: :rspec do %>
57
+ describe MyLibName do
58
+ it 'does what I made it do' do
59
+ described_class.new('some data').result.should == 'some cool result'
60
+ end
61
+ end
62
+ <%% end %>
63
+
64
+ Run `$ mountain_berry_fields Readme.mountain_berry_fields.md` to generate `Readme.md`
65
+
66
+ # MyLibName
67
+
68
+ describe MyLibName do
69
+ it 'does what I made it do' do
70
+ described_class.new('some data').result.should == 'some cool result'
71
+ end
72
+ end
73
+
74
+ And an rspec error:
75
+
76
+ FAILURE: an example
77
+ MyLibName does what I made it do:
78
+ expected: "some cool result"
79
+ got: "some unexpected result" (using ==)
80
+
81
+ backtrace:
82
+ /spec.rb:8:in `block (2 levels) in <top (required)>'
83
+ <% end %>
84
+
85
+ Realworld [example](https://github.com/JoshCheek/surrogate/blob/b7ad4d3cd5ce2e3b8bf44c3743436e4d614b1991/Readme.md.mountain_berry_fields#L254-258).
86
+
87
+ ### Setup blocks
88
+
89
+ You may need to do something to setup the environment for the tests (e.g. load the lib your examples are using)
90
+ Do that with a setup block:
91
+
92
+ <% test 'setup blocks', with: :requires_lib do %>
93
+ <%% setup do %>
94
+ $LOAD_PATH.unshift File.expand_path '../lib', __FILE__
95
+ require 'my_lib_name'
96
+ <%% end %>
97
+ <% end %>
98
+
99
+ This will not show up anywhere in the generated file. It will be prepended before each code sample when running tests.
100
+
101
+ Realworld [example](https://github.com/JoshCheek/deject/blob/8eb0d92949318cf4ef87c2b1a2070328024b0196/Readme.md.mountain_berry_fields#L22-25).
102
+
103
+ ### Context blocks
104
+
105
+ Some examples may need to be executed within a context. Use a context block for that.
106
+ Use the `__CODE__` macro to indicate where the code should go relative to this context.
107
+
108
+ <% test 'context block', with: :generic_mbf do %>
109
+ <%% context 'a user named Carlita' do %>
110
+ user = Struct.new(:name).new 'Carlita'
111
+ __CODE__
112
+ <%% end %>
113
+
114
+ <%% test 'users have a name', context: 'a user named Carlita', with: :magic_comments do %>
115
+ user.name # => "Carlita"
116
+ <%% end %>
117
+ <% end %>
118
+
119
+ Context blocks can, themselves, be rendered into a context `<%% context 'current', context: "my context's context" do %>`
120
+
121
+ Realworld [example](https://github.com/JoshCheek/surrogate/blob/b7ad4d3cd5ce2e3b8bf44c3743436e4d614b1991/Readme.md.mountain_berry_fields#L237-258).
122
+
123
+ ### Rake Task
124
+
125
+ If you want to add this as part of your build, there is a rake task:
126
+
127
+ ```ruby
128
+ <%# this is the only one I'm going to test here. Maybe in the future, a gem for strategies specifically targeting rake %>
129
+ <% test 'rake task', with: :task_named_mbf do %>
130
+ require 'mountain_berry_fields/rake_task'
131
+ MountainBerryFields::RakeTask.new(:mbf, 'Readme.mountain_berry_fields.md')
132
+ <% end %>
133
+ ```
134
+
135
+ which will allow you to say `$ rake mbf`. You could then add it to your default task with
136
+ `task default: :mbf`, or have whatever task runs your tests just execute it at the end.
137
+
138
+ Realworld [example](https://github.com/JoshCheek/surrogate/blob/b7ad4d3cd5ce2e3b8bf44c3743436e4d614b1991/Rakefile#L13-17).
139
+
140
+ ### Creating your own test strategy
141
+
142
+ I've written the magic_comments and rspec strategies. You can write your own that do
143
+ whatever interesting thing you've thought of.
144
+
145
+ If you want it to be a gem, then the strategy needs to be in the file
146
+ `mountain_berry_fields/test/your_strategy.rb`. Mountain Berry Fields
147
+ will automatically load files at these paths. If your strategy is not a gem,
148
+ then it is up to you to ensure the code defining the strategy is loaded.
149
+
150
+ Any strategy can be made accessible to the .mountain_berry_fields file like this:
151
+ `<% test('registering', with: :register_your_strategy){ %>MountainBerryFields::Test::Strategy.register :your_strategy, YourStrategy<%}%>`
152
+ And then accessed by `<%% test 'testname', with: :your_strategy do %>`
153
+
154
+ Strategies will be initialized with the code to test, and are expected to
155
+ implement `#pass?` which returns a boolean of whether the code passes according
156
+ to that strategy, and `#failure_message` which will used to describe why the spec
157
+ failed to users.
158
+
159
+ Realworld gem [example](https://github.com/JoshCheek/mountain_berry_fields-rspec/blob/cc6364ad106a7c65822542709bc5676bfb0b2c07/lib/mountain_berry_fields/test/rspec.rb).
160
+ Realworld non-gem [example](https://github.com/JoshCheek/mountain_berry_fields/blob/be751536c8b0f94c84b09167fa83616b94b13b12/readme_helper.rb),
161
+ and the code that [loads](https://github.com/JoshCheek/mountain_berry_fields/blob/754c3fb9d26779e38c01e15999ea6b86137372a2/Readme.md.mountain_berry_fields#L1) it.
162
+
163
+ ### About the name
164
+
165
+ I am often asked why I picked this name. I make things like this for me, because I have decided that they have value.
166
+ I felt the need to remind myself of that so I chose a name that no one would realisitcally choose,
167
+ to remind myself of the fact that no one could tell me I couldn't choose it.
168
+
169
+ The phrase "Mountain berry fields" is a lyric in a [song](http://www.myspace.com/joyelectric/music/songs/birds-will-sing-forever-christian-songs-album-version-34576758) that makes me happy.
170
+
171
+ If it bothers you: `$ alias mbf=mountain_berry_fields`
172
+
173
+ ## TODO
174
+ * set it up on Travis
175
+
176
+ ## Features to add for v2
177
+
178
+ Note that my use cases are to be able to test Deject and Surrogate,
179
+ which this currently does quite nicely. As a result, I have no imminent
180
+ need for any of these features, and so they are not a priority for me.
181
+ If you have a need for them (or for other features), let me know and that
182
+ will cause it to be a much higher priority for me. Alternatively,
183
+ pull requests that add them, fix bugs, or generally make it better,
184
+ are more than welcome.
185
+
186
+ * contexts should be lazy (can define context after a block that uses it)
187
+ * should be able to pass options to the initializer
188
+ * enable the test strategy to decide what should be returned
189
+ * support for multiple input files
190
+ * FLAGS:
191
+ * * -o set up input files so they don't need a .mountain_berry_fields in their name (output filename is provided, so input filename needs no naming conventions)
192
+ * * -s list all known test strategies
193
+ * * -v version
194
+ * * -c check syntax (no output, thus also no input filename restrictions)
195
+ * * -e flag for outputting erb (e.g. when it gives weird ass _buf error)
196
+ * * -h to display this menu
197
+ * * ?? to display the code that was passed to the test, along with the failure