buildr 1.3.3 → 1.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. data/CHANGELOG +76 -0
  2. data/NOTICE +1 -1
  3. data/README.rdoc +9 -21
  4. data/Rakefile +20 -37
  5. data/_buildr +3 -12
  6. data/{doc/print.toc.yaml → _jbuildr} +14 -14
  7. data/addon/buildr/cobertura.rb +5 -219
  8. data/addon/buildr/drb.rb +281 -0
  9. data/addon/buildr/emma.rb +5 -221
  10. data/addon/buildr/nailgun.rb +93 -689
  11. data/bin/buildr +0 -9
  12. data/buildr.buildfile +4 -4
  13. data/buildr.gemspec +27 -21
  14. data/doc/_layouts/default.html +82 -0
  15. data/doc/_layouts/preface.html +22 -0
  16. data/doc/{pages/artifacts.textile → artifacts.textile} +82 -42
  17. data/doc/{pages/building.textile → building.textile} +89 -47
  18. data/doc/{pages/contributing.textile → contributing.textile} +53 -45
  19. data/doc/css/default.css +6 -5
  20. data/doc/css/print.css +17 -24
  21. data/doc/css/syntax.css +7 -36
  22. data/doc/download.textile +78 -0
  23. data/doc/{pages/extending.textile → extending.textile} +45 -24
  24. data/doc/{pages/getting_started.textile → getting_started.textile} +146 -88
  25. data/doc/images/asf-logo.gif +0 -0
  26. data/doc/images/note.png +0 -0
  27. data/doc/index.textile +47 -0
  28. data/doc/{pages/languages.textile → languages.textile} +108 -54
  29. data/doc/mailing_lists.textile +25 -0
  30. data/doc/{pages/more_stuff.textile → more_stuff.textile} +152 -73
  31. data/doc/{pages/packaging.textile → packaging.textile} +181 -96
  32. data/doc/preface.textile +28 -0
  33. data/doc/{pages/projects.textile → projects.textile} +55 -40
  34. data/doc/scripts/buildr-git.rb +364 -264
  35. data/doc/scripts/gitflow.rb +296 -0
  36. data/doc/scripts/install-jruby.sh +2 -2
  37. data/doc/scripts/install-linux.sh +6 -6
  38. data/doc/scripts/install-osx.sh +2 -2
  39. data/doc/{pages/settings_profiles.textile → settings_profiles.textile} +83 -45
  40. data/doc/{pages/testing.textile → testing.textile} +77 -41
  41. data/lib/buildr.rb +5 -5
  42. data/lib/buildr/core.rb +2 -0
  43. data/lib/buildr/core/application.rb +321 -151
  44. data/lib/buildr/core/build.rb +298 -167
  45. data/lib/buildr/core/checks.rb +4 -132
  46. data/lib/buildr/core/common.rb +1 -5
  47. data/lib/buildr/core/compile.rb +3 -9
  48. data/lib/buildr/core/environment.rb +12 -3
  49. data/lib/buildr/core/filter.rb +20 -18
  50. data/lib/buildr/core/generate.rb +36 -36
  51. data/lib/buildr/core/help.rb +2 -1
  52. data/lib/buildr/core/osx.rb +46 -0
  53. data/lib/buildr/core/progressbar.rb +1 -1
  54. data/lib/buildr/core/project.rb +7 -34
  55. data/lib/buildr/core/test.rb +12 -6
  56. data/lib/buildr/core/transports.rb +13 -11
  57. data/lib/buildr/core/util.rb +14 -23
  58. data/lib/buildr/groovy/bdd.rb +3 -2
  59. data/lib/buildr/groovy/compiler.rb +1 -1
  60. data/lib/buildr/ide/eclipse.rb +31 -21
  61. data/lib/buildr/ide/idea.rb +3 -2
  62. data/lib/buildr/ide/idea7x.rb +6 -4
  63. data/lib/buildr/java/ant.rb +3 -1
  64. data/lib/buildr/java/bdd.rb +9 -7
  65. data/lib/buildr/java/cobertura.rb +243 -0
  66. data/lib/buildr/java/compiler.rb +5 -4
  67. data/lib/buildr/java/emma.rb +244 -0
  68. data/lib/buildr/java/packaging.rb +11 -8
  69. data/lib/buildr/java/pom.rb +0 -4
  70. data/lib/buildr/java/rjb.rb +1 -1
  71. data/lib/buildr/java/test_result.rb +5 -7
  72. data/lib/buildr/java/tests.rb +17 -11
  73. data/lib/buildr/packaging.rb +5 -2
  74. data/lib/buildr/packaging/archive.rb +488 -0
  75. data/lib/buildr/packaging/artifact.rb +48 -29
  76. data/lib/buildr/packaging/artifact_namespace.rb +6 -6
  77. data/lib/buildr/packaging/gems.rb +4 -4
  78. data/lib/buildr/packaging/package.rb +3 -2
  79. data/lib/buildr/packaging/tar.rb +85 -3
  80. data/lib/buildr/packaging/version_requirement.rb +172 -0
  81. data/lib/buildr/packaging/zip.rb +24 -682
  82. data/lib/buildr/packaging/ziptask.rb +313 -0
  83. data/lib/buildr/scala.rb +5 -0
  84. data/lib/buildr/scala/bdd.rb +100 -0
  85. data/lib/buildr/scala/compiler.rb +45 -4
  86. data/lib/buildr/scala/tests.rb +12 -59
  87. data/rakelib/checks.rake +57 -0
  88. data/rakelib/doc.rake +58 -68
  89. data/rakelib/jekylltask.rb +110 -0
  90. data/rakelib/package.rake +35 -37
  91. data/rakelib/release.rake +119 -35
  92. data/rakelib/rspec.rake +29 -39
  93. data/rakelib/setup.rake +21 -59
  94. data/rakelib/stage.rake +184 -26
  95. data/spec/addon/drb_spec.rb +328 -0
  96. data/spec/core/application_spec.rb +32 -25
  97. data/spec/core/build_spec.rb +336 -126
  98. data/spec/core/checks_spec.rb +292 -310
  99. data/spec/core/common_spec.rb +8 -2
  100. data/spec/core/compile_spec.rb +17 -1
  101. data/spec/core/generate_spec.rb +3 -3
  102. data/spec/core/project_spec.rb +18 -10
  103. data/spec/core/test_spec.rb +8 -1
  104. data/spec/core/transport_spec.rb +40 -3
  105. data/spec/core/util_spec.rb +67 -0
  106. data/spec/ide/eclipse_spec.rb +96 -28
  107. data/spec/ide/idea7x_spec.rb +84 -0
  108. data/spec/java/ant.rb +5 -0
  109. data/spec/java/bdd_spec.rb +12 -3
  110. data/spec/{addon → java}/cobertura_spec.rb +6 -6
  111. data/spec/{addon → java}/emma_spec.rb +5 -6
  112. data/spec/java/java_spec.rb +12 -2
  113. data/spec/java/packaging_spec.rb +31 -2
  114. data/spec/{addon → java}/test_coverage_spec.rb +3 -3
  115. data/spec/java/tests_spec.rb +5 -0
  116. data/spec/packaging/archive_spec.rb +11 -1
  117. data/spec/{core → packaging}/artifact_namespace_spec.rb +10 -2
  118. data/spec/packaging/artifact_spec.rb +44 -3
  119. data/spec/packaging/packaging_spec.rb +1 -1
  120. data/spec/sandbox.rb +17 -14
  121. data/spec/scala/bdd_spec.rb +150 -0
  122. data/spec/scala/compiler_spec.rb +27 -0
  123. data/spec/scala/scala.rb +38 -0
  124. data/spec/scala/tests_spec.rb +78 -33
  125. data/spec/spec_helpers.rb +29 -5
  126. data/spec/version_requirement_spec.rb +6 -0
  127. metadata +175 -171
  128. data/DISCLAIMER +0 -7
  129. data/doc/images/apache-incubator-logo.png +0 -0
  130. data/doc/pages/download.textile +0 -51
  131. data/doc/pages/index.textile +0 -42
  132. data/doc/pages/mailing_lists.textile +0 -17
  133. data/doc/pages/recipes.textile +0 -103
  134. data/doc/pages/troubleshooting.textile +0 -103
  135. data/doc/pages/whats_new.textile +0 -323
  136. data/doc/print.haml +0 -51
  137. data/doc/site.haml +0 -56
  138. data/doc/site.toc.yaml +0 -47
  139. data/etc/git-svn-authors +0 -16
  140. data/lib/buildr/core/application_cli.rb +0 -139
  141. data/rakelib/apache.rake +0 -191
  142. data/rakelib/changelog.rake +0 -57
  143. data/rakelib/rubyforge.rake +0 -53
  144. data/rakelib/scm.rake +0 -49
@@ -1,9 +1,13 @@
1
- h1. Testing
1
+ ---
2
+ layout: default
3
+ title: Testing
4
+ ---
5
+
2
6
 
3
7
  Untested code is broken code, so we take testing seriously. Off the bat you get to use either JUnit or TestNG for writing unit tests and integration tests. And you can also add your own framework, or even script tests using Ruby. But= first, let's start with the basics.
4
8
 
5
9
 
6
- h2. Writing Tests
10
+ h2(#writing). Writing Tests
7
11
 
8
12
  Each project has a @TestTask@ that you can access using the @test@ method. @TestTask@ reflects on the fact that each project has one task responsible for getting the tests to run and acting on the results. But in fact there are several tasks that do all the work, and a @test@ task coordinates all of that.
9
13
 
@@ -18,86 +22,106 @@ Once compiled, the @test@ task runs all the tests.
18
22
  Different languages use different test frameworks. You can find out more about available test frameworks in the "Languages":languages.html section.
19
23
 
20
24
 
21
- h2. Excluding Tests and Ignoring Failures
25
+ h2(#ignoring). Excluding Tests and Ignoring Failures
22
26
 
23
27
  If you have a lot of tests that are failing or just hanging there collecting dusts, you can tell Buildr to ignore them. You can either tell Buildr to only run specific tests, for example:
24
28
 
25
- {{{!ruby
29
+ <notextile>
30
+ {% highlight ruby %}
26
31
  test.include 'com.acme.tests.passing.*'
27
- }}}
32
+ {% endhighlight %}
33
+ </notextile>
28
34
 
29
35
  Or tell it to exclude specific tests, for example:
30
36
 
31
- {{{!ruby
37
+ <notextile>
38
+ {% highlight ruby %}
32
39
  test.exclude '*FailingTest', '*FailingWorseTest'
33
- }}}
40
+ {% endhighlight %}
41
+ </notextile>
34
42
 
35
43
  Note that we're always using the package qualified class name, and you can use star (@*@) to substitute for any set of characters.
36
44
 
37
45
  When tests fail, Buildr fails the @test@ task. This is usually a good thing, but you can also tell Buildr to ignore failures by resetting the @:fail_on_failure@ option:
38
46
 
39
- {{{!ruby
47
+ <notextile>
48
+ {% highlight ruby %}
40
49
  test.using :fail_on_failure=>false
41
- }}}
50
+ {% endhighlight %}
51
+ </notextile>
42
52
 
43
53
  Besides giving you a free pass to ignore failures, you can use it for other causes, for example, to be somewhat forgiving:
44
54
 
45
- {{{!ruby
55
+ <notextile>
56
+ {% highlight ruby %}
46
57
  test do
47
58
  fail 'More than 3 tests failed!' if test.failed_tests.size > 3
48
59
  end
49
- }}}
60
+ {% endhighlight %}
61
+ </notextile>
50
62
 
51
63
  The @failed_tests@ collection holds the names of all classes with failed tests. And there's @classes@, which holds the names of all test classes. Ruby arithmetic allows you to get the name of all passed test classes with a simple @test.classes – test.failed_tests@. We'll let you imagine creative use for these two.
52
64
 
53
65
 
54
- h2. Running Tests
66
+ h2(#running). Running Tests
55
67
 
56
68
  It's a good idea to run tests every time you change the source code, so we wired the @build@ task to run the @test@ task at the end of the build. And conveniently enough, the @build@ task is the default task, so another way to build changes in your code and run your tests:
57
69
 
58
- {{{!sh
70
+ <notextile>
71
+ {% highlight sh %}
59
72
  $ buildr
60
- }}}
73
+ {% endhighlight %}
74
+ </notextile>
61
75
 
62
76
  That only works with the local @build@ task and any local task that depends on it, like @package@, @install@ and @upload@. Each project also has its own @build@ task that does not invoke the @test@ task, so @buildr build@ will run the tests cases, but @buildr foo:build@ will not.
63
77
 
64
78
  While it's a good idea to always run your tests, it's not always possible. There are two ways you can get @build@ to not run the @test@ task. You can set the environment variable @test@ to @no@ (but @skip@ and @off@ will also work). You can do that when running Buildr:
65
79
 
66
- {{{!sh
80
+ <notextile>
81
+ {% highlight sh %}
67
82
  $ buildr test=no
68
- }}}
83
+ {% endhighlight %}
84
+ </notextile>
69
85
 
70
86
  Or set it once in your environment:
71
87
 
72
- {{{!sh
88
+ <notextile>
89
+ {% highlight sh %}
73
90
  $ export TEST=no
74
91
  $ buildr
75
- }}}
92
+ {% endhighlight %}
93
+ </notextile>
76
94
 
77
95
  If you're feeling really adventurous, you can also disable tests from your Buildfile or @buildr.rb@ file, by setting @options.test = false@. We didn't say it's a good idea, we're just giving you the option.
78
96
 
79
97
  The @test@ task is just smart enough to run all the tests it finds, but will accept include/exclude patterns. Often enough you're only working on one broken test and you only want to run that one test. Better than changing your Buildfile, you can run the @test@ task with a pattern. For example:
80
98
 
81
- {{{!sh
99
+ <notextile>
100
+ {% highlight sh %}
82
101
  $ buildr test:KillerAppTest
83
- }}}
102
+ {% endhighlight %}
103
+ </notextile>
84
104
 
85
105
  Buildr will then run only tests that match the pattern @KillerAppTest@. It uses pattern matching, so @test:Foo@ will run @com.acme.FooTest@ and @com.acme.FooBarTest@. With Java, you can use this to pick a class name, or a package name to run all tests in that package, or any such combination. In fact, you can specify several patterns separated with commas. For example:
86
106
 
87
- {{{!sh
107
+ <notextile>
108
+ {% highlight sh %}
88
109
  $ buildr test:FooTest,BarTest
89
- }}}
110
+ {% endhighlight %}
111
+ </notextile>
90
112
 
91
113
  As you probably noticed, Buildr will stop your build at the first test that fails. We think it's a good idea, except when it's not. If you're using a continuous build system, you'll want a report of all the failed tests without stopping at the first failure. To make that happen, set the environment variable @test@ to "all", or the Buildr @options.test@ option to @:all@. For example:
92
114
 
93
- {{{!sh
115
+ <notextile>
116
+ {% highlight sh %}
94
117
  $ buildr package test=all
95
- }}}
118
+ {% endhighlight %}
119
+ </notextile>
96
120
 
97
121
  We're using @package@ and not @build@ above. When using a continuous build system, you want to make sure that packages are created, contain the right files, and also run the integration tests.
98
122
 
99
123
 
100
- h2. Integration Tests
124
+ h2(#integration). Integration Tests
101
125
 
102
126
  So far we talked about unit tests. Unit tests are run in isolation on the specific project they test, in an isolated environment, generally with minimal setup and teardown. You get a sense of that when we told you tests run after the @build@ task, and include JMock in the dependency list.
103
127
 
@@ -105,44 +129,52 @@ In contrast, integration tests are run with a number of components, in an enviro
105
129
 
106
130
  You write integration tests much the same way as you write unit tests, using @test.compile@ and @test.resources@. However, you need to tell Buildr that your tests will execute during integration test. To do so, add the following line in your project definition:
107
131
 
108
- {{{!ruby
132
+ <notextile>
133
+ {% highlight ruby %}
109
134
  test.using :integration
110
- }}}
135
+ {% endhighlight %}
136
+ </notextile>
111
137
 
112
138
  Typically you'll use unit tests in projects that create internal modules, such as JARs, and integration tests in projects that create components, such as WARs and EARs. You only need to use the @:integration@ option with the later.
113
139
 
114
140
  To run integration tests on the current project:
115
141
 
116
- {{{!sh
142
+ <notextile>
143
+ {% highlight sh %}
117
144
  $ buildr integration
118
- }}}
145
+ {% endhighlight %}
146
+ </notextile>
119
147
 
120
148
  You can also run specific tests cases, for example:
121
149
 
122
- {{{!sh
150
+ <notextile>
151
+ {% highlight sh %}
123
152
  $ buildr integration:ClientTest
124
- }}}
153
+ {% endhighlight %}
154
+ </notextile>
125
155
 
126
156
  If you run the @package@ task (or any task that depends on it, like @install@ and @upload@), Buildr will first run the @build@ task and all its unit tests, and then create the packages and run the integration tests. That gives you full coverage for your tests and ready to release packages. As with unit tests, you can set the environment variable @test@ to "no" to skip integration tests, or "all" to ignore failures.
127
157
 
128
158
 
129
- h2. Using Setup and Teardown
159
+ h2(#setup_teardown). Using Setup and Teardown
130
160
 
131
161
  Some tests need you to setup an environment before they run, and tear it down afterwards. The test frameworks (JUnit, TestNG) allow you to do that for each test. Buildr provides two additional mechanisms for dealing with more complicated setup and teardown procedures.
132
162
 
133
163
  Integration tests run a setup task before the tests, and a teardown task afterwards. You can use this task to setup a Web server for testing your Web components, or a database server for testing persistence. You can access either task by calling @integration.setup@ and @integration.teardown@. For example:
134
164
 
135
- {{{!ruby
165
+ <notextile>
166
+ {% highlight ruby %}
136
167
  integration.setup { server.start ; server.deploy }
137
168
  integration.teardown { server.stop }
138
- }}}
169
+ {% endhighlight %}
170
+ </notextile>
139
171
 
140
172
  Depending on your build, you may want to enhance the setup/teardown tasks from within a project, for example, to populate the database with data used by that project's test, or from outside the project definition, for example, to start and stop the Web server.
141
173
 
142
174
  Likewise, each project has its own setup and teardown tasks that are run before and after tests for that specific project. You can access these tasks using @test.setup@ and @test.teardown@.
143
175
 
144
176
 
145
- h2. Testing Your Build
177
+ h2(#checks). Testing Your Build
146
178
 
147
179
  So you got the build running and all the tests pass, binaries are shipping when you find out some glaring omissions. The license file is empty, the localized messages for Japanese are missing, the CSS files are not where you expect them to be. The fact is, some errors slip by unit and integration tests. So how do we make sure the same mistake doesn't happen again?
148
180
 
@@ -150,7 +182,8 @@ Each project has a @check@ task that runs just after packaging. You can use thi
150
182
 
151
183
  You use the @check@ method to express and expectation. Buildr will then run all these expectations against your project, and fail at the first expectation that doesn't match. An expectation says three things. Let's look at a few examples:
152
184
 
153
- {{{!ruby
185
+ <notextile>
186
+ {% highlight ruby %}
154
187
  check package(:war), 'should exist' do
155
188
  it.should exist
156
189
  end
@@ -172,17 +205,20 @@ end
172
205
  check file('target/classes/killerapp/Code.class'), 'should exist' do
173
206
  it.should exist
174
207
  end
175
- }}}
208
+ {% endhighlight %}
209
+ </notextile>
176
210
 
177
211
  The first argument is the subject, or the project if you skip the first argument. The second argument is the description, optional, but we recommend using it. The method @it@ returns the subject.
178
212
 
179
213
  You can also write the first expectation like this:
180
214
 
181
- {{{!ruby
215
+ <notextile>
216
+ {% highlight ruby %}
182
217
  check do
183
218
  package(:jar).should exist
184
219
  end
185
- }}}
220
+ {% endhighlight %}
221
+ </notextile>
186
222
 
187
223
  We recommend using the subject and description, they make your build easier to read and maintain, and produce better error messages.
188
224
 
@@ -195,14 +231,14 @@ Buildr provides the following matchers:
195
231
  | @empty@ | Given a file task checks that the file (or directory) is empty. |
196
232
  | @contain@ | Given a file task referencing a file, checks its contents, using string or regular expression. For a file task referencing a directory, checks that it contains the specified files; global patterns using @*@ and @**@ are allowed. |
197
233
 
198
- All these matchers operate against a file task. If you run them against a ZipTask (including JAR, WAR, etc) they can also check the contents of the ZIP file. And as you can see in the examples above, you can also run them against a path in a ZIP file, checking its contents as if it was a directory, or against an entry in a ZIP file, checking the content of that file.
234
+ All these matchers operate against a file task. If you run them against a ZipTask (including JAR, WAR, etc) or a TarTask, they can also check the contents of the archive. And as you can see in the examples above, you can also run them against a path in an archive, checking its contents as if it was a directory, or against an entry in an archive, checking the content of that file.
199
235
 
200
236
  p(note). The @package@ method returns a package task based on packaging type, identifier, group, version and classifier. The last four are inferred, but if you create a package with different specifications (for example, you specify a classifier) your checks must call @package@ with the same qualifying arguments to return the very same package task.
201
237
 
202
238
  Buildr expectations are based on RSpec. "RSpec":http://rspec.info/ is the behavior-driven development framework we use to test Buildr itself. Check the RSpec documentation if want to see all the supported matchers, or want to write your own.
203
239
 
204
240
 
205
- h2. Behaviour-Driven Development
241
+ h2(#bdd). Behaviour-Driven Development
206
242
 
207
243
  Buildr supports several Behaviour-Driven Development(BDD) frameworks for testing your projects. Buildr follows each framework naming conventions, searching for files under the @src/spec/{lang}@ directory.
208
244
 
@@ -14,7 +14,7 @@
14
14
  # the License.
15
15
 
16
16
  module Buildr
17
- VERSION = '1.3.3'.freeze
17
+ VERSION = '1.3.4'.freeze
18
18
  end
19
19
 
20
20
  require 'buildr/core'
@@ -28,8 +28,8 @@ module Buildr ; extend self ; end
28
28
  # The Buildfile object (self) has access to all the Buildr methods and constants.
29
29
  class << self ; include Buildr ; end
30
30
  class Object #:nodoc:
31
- Buildr.constants.each { |c| const_set c, Buildr.const_get(c) unless const_defined?(c) }
31
+ Buildr.constants.each do |name|
32
+ const = Buildr.const_get(name)
33
+ const_set name, const if const.is_a?(Module)
34
+ end
32
35
  end
33
-
34
- # Prevent RSpec runner from running at_exit.
35
- require 'spec'
@@ -24,4 +24,6 @@ require 'buildr/core/filter'
24
24
  require 'buildr/core/compile'
25
25
  require 'buildr/core/test'
26
26
  require 'buildr/core/checks'
27
+ require 'buildr/core/transports'
27
28
  require 'buildr/core/generate'
29
+ require 'buildr/core/osx' if RUBY_PLATFORM =~ /darwin/
@@ -13,6 +13,7 @@
13
13
  # License for the specific language governing permissions and limitations under
14
14
  # the License.
15
15
 
16
+
16
17
  # Portion of this file derived from Rake.
17
18
  # Copyright (c) 2003, 2004 Jim Weirich
18
19
  #
@@ -35,15 +36,15 @@
35
36
  # SOFTWARE.
36
37
 
37
38
 
38
- require 'highline/import'
39
39
  require 'rake'
40
+ require 'highline/import'
40
41
  require 'rubygems/source_info_cache'
41
- require 'buildr/core/application_cli'
42
42
  require 'buildr/core/util'
43
+ Gem.autoload :SourceInfoCache, 'rubygems/source_info_cache'
43
44
 
44
45
 
45
46
  # Gem::user_home is nice, but ENV['HOME'] lets you override from the environment.
46
- ENV["HOME"] ||= File.expand_path(Gem::user_home)
47
+ ENV['HOME'] ||= File.expand_path(Gem::user_home)
47
48
  ENV['BUILDR_ENV'] ||= 'development'
48
49
 
49
50
 
@@ -68,19 +69,22 @@ module Buildr
68
69
 
69
70
  def initialize(application) #:nodoc:
70
71
  @application = application
71
- @user = load_from('settings', @application.home_dir)
72
- @build = load_from('build')
73
- @profiles = load_from('profiles')
74
72
  end
75
73
 
76
74
  # User settings loaded from setting.yaml file in user's home directory.
77
- attr_reader :user
75
+ def user
76
+ @user ||= load_from('settings', @application.home_dir)
77
+ end
78
78
 
79
79
  # Build settings loaded from build.yaml file in build directory.
80
- attr_reader :build
80
+ def build
81
+ @build ||= load_from('build')
82
+ end
81
83
 
82
84
  # Profiles loaded from profiles.yaml file in build directory.
83
- attr_reader :profiles
85
+ def profiles
86
+ @profiles ||= load_from('profiles')
87
+ end
84
88
 
85
89
  # :call-seq:
86
90
  # profile => hash
@@ -92,9 +96,12 @@ module Buildr
92
96
 
93
97
  private
94
98
 
95
- def load_from(base_name, dir = nil)
96
- base_name = File.expand_path(base_name, dir) if dir
97
- file_name = ['yaml', 'yml'].map { |ext| "#{base_name}.#{ext}" }.find { |fn| File.exist?(fn) }
99
+ def load_from(name, path = nil)
100
+ unless path
101
+ fail "Internal error: attempting to access local setting before buildfile located" unless @application.rakefile
102
+ path = File.dirname(@application.rakefile)
103
+ end
104
+ file_name = ['yaml', 'yml'].map { |ext| File.join(path, "#{name}.#{ext}") }.find { |fn| File.exist?(fn) }
98
105
  return {} unless file_name
99
106
  yaml = YAML.load(File.read(file_name)) || {}
100
107
  fail "Expecting #{file_name} to be a map (name: value)!" unless Hash === yaml
@@ -107,28 +114,41 @@ module Buildr
107
114
 
108
115
  class Application < Rake::Application #:nodoc:
109
116
 
117
+ # Deprecated: rakefile/Rakefile, removed in 1.5
110
118
  DEFAULT_BUILDFILES = ['buildfile', 'Buildfile'] + DEFAULT_RAKEFILES
111
119
 
112
- include CommandLineInterface
113
-
114
120
  attr_reader :rakefiles, :requires
115
121
  private :rakefiles, :requires
116
122
 
117
123
  def initialize
118
124
  super
119
- @rakefiles = DEFAULT_BUILDFILES
120
- @name = 'Buildr'
121
- @requires = []
125
+ @rakefiles = DEFAULT_BUILDFILES.dup
122
126
  @top_level_tasks = []
123
- parse_options
124
- collect_tasks
125
127
  @home_dir = File.expand_path('.buildr', ENV['HOME'])
126
- mkpath @home_dir, :verbose=>false unless File.exist?(@home_dir)
127
- @environment = ENV['BUILDR_ENV'] ||= 'development'
128
+ mkpath @home_dir unless File.exist?(@home_dir)
129
+ @settings = Settings.new(self)
128
130
  @on_completion = []
129
131
  @on_failure = []
130
132
  end
131
133
 
134
+ def run
135
+ standard_exception_handling do
136
+ init 'Buildr'
137
+ load_buildfile
138
+ top_level
139
+ end
140
+ end
141
+
142
+ # Not for external consumption.
143
+ def switch_to_namespace(names) #:nodoc:
144
+ current, @scope = @scope, names
145
+ begin
146
+ yield
147
+ ensure
148
+ @scope = current
149
+ end
150
+ end
151
+
132
152
  # Returns list of Gems associated with this buildfile, as listed in build.yaml.
133
153
  # Each entry is of type Gem::Specification.
134
154
  attr_reader :gems
@@ -137,13 +157,12 @@ module Buildr
137
157
  attr_reader :home_dir
138
158
 
139
159
  # Copied from BUILD_ENV.
140
- attr_reader :environment
160
+ def environment
161
+ ENV['BUILDR_ENV']
162
+ end
141
163
 
142
164
  # Returns the Settings associated with this build.
143
- def settings
144
- fail "Internal error: Called Buildr.settings before buildfile located" unless rakefile
145
- @settings ||= Settings.new(self)
146
- end
165
+ attr_reader :settings
147
166
 
148
167
  # :call-seq:
149
168
  # buildfile
@@ -151,28 +170,13 @@ module Buildr
151
170
  def buildfile
152
171
  @buildfile_task ||= BuildfileTask.define_task(File.expand_path(rakefile))
153
172
  end
154
-
173
+
155
174
  # Files that complement the buildfile itself
156
175
  def build_files #:nodoc:
176
+ deprecated 'Please call buildfile.prerequisites instead'
157
177
  buildfile.prerequisites
158
178
  end
159
179
 
160
- def run
161
- standard_exception_handling do
162
- find_buildfile
163
- load_gems
164
- load_artifacts
165
- load_tasks
166
- load_requires
167
- load_buildfile
168
- load_imports
169
- task('buildr:initialize').invoke
170
- top_level
171
- end
172
- title, message = 'Your build has completed', "#{Dir.pwd}\nbuildr #{@top_level_tasks.join(' ')}"
173
- @on_completion.each { |block| block.call(title, message) rescue nil }
174
- end
175
-
176
180
  # Yields to block on successful completion. Primarily used for notifications.
177
181
  def on_completion(&block)
178
182
  @on_completion << block
@@ -183,16 +187,6 @@ module Buildr
183
187
  @on_failure << block
184
188
  end
185
189
 
186
- # Not for external consumption.
187
- def switch_to_namespace(names) #:nodoc:
188
- current, @scope = @scope, names
189
- begin
190
- yield
191
- ensure
192
- @scope = current
193
- end
194
- end
195
-
196
190
  # :call-seq:
197
191
  # deprecated(message)
198
192
  #
@@ -213,30 +207,204 @@ module Buildr
213
207
  end
214
208
  end
215
209
 
216
- private
210
+ protected
211
+
212
+ def load_buildfile # replaces load_rakefile
213
+ standard_exception_handling do
214
+ find_buildfile
215
+ load_gems
216
+ load_artifact_ns
217
+ load_tasks
218
+ raw_load_buildfile
219
+ end
220
+ end
217
221
 
218
- # Returns Gem::Specification for every listed and installed Gem, Gem::Dependency
219
- # for listed and uninstalled Gem, which is the installed before loading the buildfile.
220
- def listed_gems #:nodoc:
221
- Array(settings.build['gems']).map do |dep|
222
- name, trail = dep.scan(/^\s*(\S*)\s*(.*)\s*$/).first
223
- versions = trail.scan(/[=><~!]{0,2}\s*[\d\.]+/)
224
- versions = ['>= 0'] if versions.empty?
225
- dep = Gem::Dependency.new(name, versions)
226
- Gem::SourceIndex.from_installed_gems.search(dep).last || dep
222
+ def top_level # adds on_completion hook
223
+ standard_exception_handling do
224
+ if options.show_tasks
225
+ display_tasks_and_comments
226
+ elsif options.show_prereqs
227
+ display_prerequisites
228
+ elsif options.execute
229
+ eval options.execute
230
+ else
231
+ @start = Time.now
232
+ top_level_tasks.each { |task_name| invoke_task(task_name) }
233
+ if verbose
234
+ elapsed = Time.now - @start
235
+ real = []
236
+ real << ('%ih' % (elapsed / 3600)) if elapsed >= 3600
237
+ real << ('%im' % ((elapsed / 60) % 60)) if elapsed >= 60
238
+ real << ('%.3fs' % (elapsed % 60))
239
+ puts $terminal.color("Completed in #{real.join}", :green)
240
+ end
241
+ # On OS X this will load Cocoa and Growl which takes half a second we
242
+ # don't want to measure, so put this after the console message.
243
+ title, message = "Your build has completed", "#{Dir.pwd}\nbuildr #{@top_level_tasks.join(' ')}"
244
+ @on_completion.each do |block|
245
+ block.call(title, message) rescue nil
246
+ end
247
+ end
227
248
  end
228
249
  end
229
250
 
230
- # Load artifact specs from the build.yaml file, making them available
231
- # by name ( ruby symbols ).
232
- def load_artifacts #:nodoc:
233
- hash = settings.build['artifacts']
234
- return unless hash
235
- raise "Expected 'artifacts' element to be a hash" unless Hash === hash
236
- # Currently we only use one artifact namespace to rule them all. (the root NS)
237
- Buildr::ArtifactNamespace.load(:root => hash)
251
+ def handle_options
252
+ options.rakelib = ['tasks']
253
+
254
+ OptionParser.new do |opts|
255
+ opts.banner = "buildr [-f rakefile] {options} targets..."
256
+ opts.separator ""
257
+ opts.separator "Options are ..."
258
+
259
+ opts.on_tail("-h", "--help", "-H", "Display this help message.") do
260
+ puts opts
261
+ exit
262
+ end
263
+ standard_buildr_options.each { |args| opts.on(*args) }
264
+ end.parse!
265
+ end
266
+
267
+ def standard_buildr_options # replaces standard_rake_options
268
+ [
269
+ ['--describe', '-D [PATTERN]', "Describe the tasks (matching optional PATTERN), then exit.",
270
+ lambda { |value|
271
+ options.show_tasks = true
272
+ options.full_description = true
273
+ options.show_task_pattern = Regexp.new(value || '')
274
+ }
275
+ ],
276
+ ['--execute', '-E CODE',
277
+ "Execute some Ruby code after loading the buildfile",
278
+ lambda { |value| options.execute = value }
279
+ ],
280
+ ['--environment', '-e ENV',
281
+ "Environment name (e.g. development, test, production).",
282
+ lambda { |value| ENV['BUILDR_ENV'] = value }
283
+ ],
284
+ ['--generate [PATH]',
285
+ "Generate buildfile from either pom.xml file or directory path.",
286
+ lambda { |value|
287
+ value ||= File.exist?('pom.xml') ? 'pom.xml' : Dir.pwd
288
+ raw_generate_buildfile value
289
+ exit
290
+ }
291
+ ],
292
+ ['--libdir', '-I LIBDIR', "Include LIBDIR in the search path for required modules.",
293
+ lambda { |value| $:.push(value) }
294
+ ],
295
+ ['--prereqs', '-P [PATTERN]', "Display the tasks and dependencies (matching optional PATTERN), then exit.",
296
+ lambda { |value|
297
+ options.show_prereqs = true
298
+ options.show_task_pattern = Regexp.new(value || '')
299
+ }
300
+ ],
301
+ ['--quiet', '-q', "Do not log messages to standard output.",
302
+ lambda { |value| verbose(false) }
303
+ ],
304
+ ['--buildfile', '-f FILE', "Use FILE as the buildfile.",
305
+ lambda { |value|
306
+ @rakefiles.clear
307
+ @rakefiles << value
308
+ }
309
+ ],
310
+ ['--rakelibdir', '--rakelib', '-R PATH',
311
+ "Auto-import any .rake files in PATH. (default is 'tasks')",
312
+ lambda { |value| options.rakelib = value.split(':') }
313
+ ],
314
+ ['--require', '-r MODULE', "Require MODULE before executing rakefile.",
315
+ lambda { |value|
316
+ begin
317
+ require value
318
+ rescue LoadError => ex
319
+ begin
320
+ rake_require value
321
+ rescue LoadError => ex2
322
+ raise ex
323
+ end
324
+ end
325
+ }
326
+ ],
327
+ ['--rules', "Trace the rules resolution.",
328
+ lambda { |value| options.trace_rules = true }
329
+ ],
330
+ ['--no-search', '--nosearch', '-N', "Do not search parent directories for the Rakefile.",
331
+ lambda { |value| options.nosearch = true }
332
+ ],
333
+ ['--silent', '-s', "Like --quiet, but also suppresses the 'in directory' announcement.",
334
+ lambda { |value|
335
+ verbose(false)
336
+ options.silent = true
337
+ }
338
+ ],
339
+ ['--tasks', '-T [PATTERN]', "Display the tasks (matching optional PATTERN) with descriptions, then exit.",
340
+ lambda { |value|
341
+ options.show_tasks = true
342
+ options.show_task_pattern = Regexp.new(value || '')
343
+ options.full_description = false
344
+ }
345
+ ],
346
+ ['--trace', '-t', "Turn on invoke/execute tracing, enable full backtrace.",
347
+ lambda { |value|
348
+ options.trace = true
349
+ verbose(true)
350
+ }
351
+ ],
352
+ ['--verbose', '-v', "Log message to standard output (default).",
353
+ lambda { |value| verbose(true) }
354
+ ],
355
+ ['--version', '-V', "Display the program version.",
356
+ lambda { |value|
357
+ puts "Buildr #{Buildr::VERSION} #{RUBY_PLATFORM[/java/] && '(JRuby '+JRUBY_VERSION+')'}"
358
+ exit
359
+ }
360
+ ]
361
+ ]
362
+ end
363
+
364
+ def find_buildfile
365
+ buildfile, location = find_rakefile_location || (tty_output? && ask_generate_buildfile)
366
+ fail "No Buildfile found (looking for: #{@rakefiles.join(', ')})" if buildfile.nil?
367
+ @rakefile = buildfile
368
+ Dir.chdir(location)
369
+ end
370
+
371
+ def ask_generate_buildfile
372
+ source = choose do |menu|
373
+ menu.header = "To use Buildr you need a buildfile. Do you want me to create one?"
374
+ menu.choice("From Maven2 POM file") { 'pom.xml' } if File.exist?('pom.xml')
375
+ menu.choice("From directory structure") { Dir.pwd }
376
+ menu.choice("Cancel") { }
377
+ end
378
+ if source
379
+ buildfile = raw_generate_buildfile(source)
380
+ [buildfile, File.dirname(buildfile)]
381
+ end
382
+ end
383
+
384
+ def raw_generate_buildfile(source)
385
+ # We need rakefile to be known, for settings.build to be accessible.
386
+ @rakefile = File.expand_path(DEFAULT_BUILDFILES.first)
387
+ fail "Buildfile already exists" if File.exist?(@rakefile) && !(tty_output? && agree('Buildfile exists, overwrite?'))
388
+ script = File.directory?(source) ? Generate.from_directory(source) : Generate.from_maven2_pom(source)
389
+ File.open @rakefile, 'w' do |file|
390
+ file.puts script
391
+ end
392
+ puts "Created #{@rakefile}" if verbose
393
+ @rakefile
238
394
  end
239
-
395
+
396
+ def raw_load_buildfile # replaces raw_load_rakefile
397
+ puts "(in #{Dir.pwd}, #{environment})" unless options.silent
398
+ load File.expand_path(@rakefile) if @rakefile && @rakefile != ''
399
+ options.rakelib.each do |rlib|
400
+ glob("#{rlib}/*.rake") do |name|
401
+ add_import name
402
+ end
403
+ end
404
+ load_imports
405
+ Buildr.projects
406
+ end
407
+
240
408
  # Load/install all Gems specified in build.yaml file.
241
409
  def load_gems #:nodoc:
242
410
  missing_deps, installed = listed_gems.partition { |gem| gem.is_a?(Gem::Dependency) }
@@ -259,42 +427,35 @@ module Buildr
259
427
  @gems = installed
260
428
  end
261
429
 
262
- def find_buildfile #:nodoc:
263
- here = original_dir
264
- Dir.chdir(here) unless Dir.pwd == here
265
- while ! have_rakefile
266
- Dir.chdir('..')
267
- if Dir.pwd == here || options.nosearch
268
- error = "No Buildfile found (looking for: #{@rakefiles.join(', ')})"
269
- if STDIN.isatty
270
- chdir(original_dir) { task('generate').invoke }
271
- exit 1
272
- else
273
- raise error
274
- end
275
- end
276
- here = Dir.pwd
430
+ # Returns Gem::Specification for every listed and installed Gem, Gem::Dependency
431
+ # for listed and uninstalled Gem, which is the installed before loading the buildfile.
432
+ def listed_gems #:nodoc:
433
+ Array(settings.build['gems']).map do |dep|
434
+ name, trail = dep.scan(/^\s*(\S*)\s*(.*)\s*$/).first
435
+ versions = trail.scan(/[=><~!]{0,2}\s*[\d\.]+/)
436
+ versions = ['>= 0'] if versions.empty?
437
+ dep = Gem::Dependency.new(name, versions)
438
+ Gem::SourceIndex.from_installed_gems.search(dep).last || dep
277
439
  end
278
440
  end
279
441
 
280
- def load_buildfile #:nodoc:
281
- info "(in #{Dir.pwd}, #{environment})"
282
- load File.expand_path(@rakefile) if @rakefile != ''
283
- buildfile.enhance @requires.select { |f| File.file?(f) }.map{ |f| File.expand_path(f) }
284
- end
285
-
286
- def load_requires #:nodoc:
287
- @requires.each { |name| require name }
442
+ # Load artifact specs from the build.yaml file, making them available
443
+ # by name ( ruby symbols ).
444
+ def load_artifact_ns #:nodoc:
445
+ hash = settings.build['artifacts']
446
+ return unless hash
447
+ raise "Expected 'artifacts' element to be a hash" unless Hash === hash
448
+ # Currently we only use one artifact namespace to rule them all. (the root NS)
449
+ Buildr::ArtifactNamespace.load(:root => hash)
288
450
  end
289
-
451
+
290
452
  # Loads buildr.rb files from users home directory and project directory.
291
453
  # Loads custom tasks from .rake files in tasks directory.
292
454
  def load_tasks #:nodoc:
455
+ # TODO: this might need to be split up, look for deprecated features, better method name.
293
456
  files = [ File.expand_path('buildr.rb', ENV['HOME']), 'buildr.rb' ].select { |file| File.exist?(file) }
294
457
  files += [ File.expand_path('buildr.rake', ENV['HOME']), File.expand_path('buildr.rake') ].
295
458
  select { |file| File.exist?(file) }.each { |file| warn "Please use '#{file.ext('rb')}' instead of '#{file}'" }
296
- #Load local tasks that can be used in the Buildfile.
297
- files += Dir[File.expand_path('tasks/*.rake')]
298
459
  files.each do |file|
299
460
  unless $LOADED_FEATURES.include?(file)
300
461
  load file
@@ -305,49 +466,68 @@ module Buildr
305
466
  true
306
467
  end
307
468
 
308
- def display_prerequisites
309
- invoke_task('buildr:initialize')
310
- tasks.each do |task|
311
- if task.name =~ options.show_task_pattern
312
- puts "buildr #{task.name}"
313
- task.prerequisites.each { |prereq| puts " #{prereq}" }
469
+ def display_tasks_and_comments
470
+ displayable_tasks = tasks.select { |t| t.comment && t.name =~ options.show_task_pattern }
471
+ if options.full_description
472
+ displayable_tasks.each do |t|
473
+ puts "buildr #{t.name_with_args}"
474
+ t.full_comment.split("\n").each do |line|
475
+ puts " #{line}"
476
+ end
477
+ puts
478
+ end
479
+ else
480
+ width = displayable_tasks.collect { |t| t.name_with_args.length }.max || 10
481
+ max_column = truncate_output? ? terminal_width - name.size - width - 7 : nil
482
+ displayable_tasks.each do |t|
483
+ printf "#{name} %-#{width}s # %s\n",
484
+ t.name_with_args, max_column ? truncate(t.comment, max_column) : t.comment
314
485
  end
315
486
  end
316
487
  end
317
-
318
- # Provide standard execption handling for the given block.
319
- def standard_exception_handling
488
+
489
+ def display_prerequisites
490
+ displayable_tasks = tasks.select { |t| t.name =~ options.show_task_pattern }
491
+ displayable_tasks.each do |t|
492
+ puts "buildr #{t.name}"
493
+ t.prerequisites.each { |pre| puts " #{pre}" }
494
+ end
495
+ end
496
+
497
+ def standard_exception_handling # adds on_failure hook
320
498
  begin
321
499
  yield
322
500
  rescue SystemExit => ex
323
501
  # Exit silently with current status
324
502
  exit(ex.status)
325
- rescue SystemExit, GetoptLong::InvalidOption => ex
326
- # Exit silently
503
+ rescue OptionParser::ParseError => ex
504
+ $stderr.puts $terminal.color(ex.message, :red)
327
505
  exit(1)
328
506
  rescue Exception => ex
329
- title, message = 'Your build failed with an error', "#{Dir.pwd}:\n#{ex.message}"
330
- @on_failure.each { |block| block.call(title, message, ex) rescue nil }
507
+ title, message = "Your build failed with an error", "#{Dir.pwd}:\n#{ex.message}"
508
+ @on_failure.each do |block|
509
+ block.call(title, message, ex) rescue nil
510
+ end
331
511
  # Exit with error message
332
- $stderr.puts "buildr aborted!"
512
+ $stderr.puts "Buildr aborted!"
333
513
  $stderr.puts $terminal.color(ex.message, :red)
334
514
  if options.trace
335
515
  $stderr.puts ex.backtrace.join("\n")
336
516
  else
337
- $stderr.puts ex.backtrace.select { |str| str =~ /#{buildfile}/ }.map { |line| $terminal.color(line, :red) }.join("\n")
517
+ $stderr.puts ex.backtrace.select { |str| str =~ /#{rakefile}/ }.map { |line| $terminal.color(line, :red) }.join("\n") if rakefile
338
518
  $stderr.puts "(See full trace by running task with --trace)"
339
519
  end
340
520
  exit(1)
341
521
  end
342
522
  end
343
-
523
+
344
524
  end
345
525
 
346
526
 
347
527
  # This task stands for the buildfile and all its associated helper files (e.g., buildr.rb, build.yaml).
348
528
  # By using this task as a prerequisite for other tasks, you can ensure these tasks will be needed
349
529
  # whenever the buildfile changes.
350
- class BuildfileTask < Rake::FileTask
530
+ class BuildfileTask < Rake::FileTask #:nodoc:
351
531
 
352
532
  def timestamp
353
533
  ([name] + prerequisites).map { |f| File.stat(f).mtime }.max rescue Time.now
@@ -357,10 +537,6 @@ module Buildr
357
537
 
358
538
  class << self
359
539
 
360
- task 'buildr:initialize' do
361
- Buildr.load_tasks_and_local_files
362
- end
363
-
364
540
  # Returns the Buildr::Application object.
365
541
  def application
366
542
  Rake.application
@@ -399,38 +575,6 @@ else
399
575
  end
400
576
 
401
577
 
402
- # Let's see if we can use Growl. We do this at the very end, loading Ruby Cocoa
403
- # could slow the build down, so later is better. We only do this when running
404
- # from the console in verbose mode.
405
- if $stdout.isatty && verbose && RUBY_PLATFORM =~ /darwin/
406
- begin
407
- require 'osx/cocoa'
408
- icon = OSX::NSApplication.sharedApplication.applicationIconImage
409
- icon = OSX::NSImage.alloc.initWithContentsOfFile(File.join(File.dirname(__FILE__), '../resources/buildr.icns'))
410
-
411
- # Register with Growl, that way you can turn notifications on/off from system preferences.
412
- OSX::NSDistributedNotificationCenter.defaultCenter.
413
- postNotificationName_object_userInfo_deliverImmediately(:GrowlApplicationRegistrationNotification, nil,
414
- { :ApplicationName=>'Buildr', :AllNotifications=>['Completed', 'Failed'],
415
- :ApplicationIcon=>icon.TIFFRepresentation }, true)
416
-
417
- notify = lambda do |type, title, message|
418
- OSX::NSDistributedNotificationCenter.defaultCenter.
419
- postNotificationName_object_userInfo_deliverImmediately(:GrowlNotification, nil,
420
- { :ApplicationName=>'Buildr', :NotificationName=>type,
421
- :NotificationTitle=>title, :NotificationDescription=>message }, true)
422
- end
423
- Buildr.application.on_completion { |title, message| notify['Completed', title, message] }
424
- Buildr.application.on_failure { |title, message, ex| notify['Failed', title, message] }
425
- rescue Exception # No growl
426
- end
427
- elsif $stdout.isatty && verbose
428
- notify = lambda { |type, title, message| $stdout.puts "[#{type}] #{title}: #{message}" }
429
- Buildr.application.on_completion { |title, message| notify['Completed', title, message] }
430
- Buildr.application.on_failure { |title, message, ex| notify['Failed', title, message] }
431
- end
432
-
433
-
434
578
  alias :warn_without_color :warn
435
579
 
436
580
  # Show warning message.
@@ -457,6 +601,13 @@ end
457
601
 
458
602
 
459
603
  module Rake #:nodoc
604
+ # Rake's circular dependency checks (InvocationChain) only applies to task prerequisites,
605
+ # all other cases result in the non too-descriptive thread sleeping error. This change can
606
+ # deal with circular dependencies that occur from direct task invocation, e.g:
607
+ # task 'foo'=>'bar'
608
+ # task 'bar' do
609
+ # task('foo').invoke
610
+ # end
460
611
  class Task #:nodoc:
461
612
  def invoke(*args)
462
613
  task_args = TaskArguments.new(arg_names, args)
@@ -487,3 +638,22 @@ module Rake #:nodoc
487
638
  end
488
639
  end
489
640
  end
641
+
642
+
643
+ module RakeFileUtils #:nodoc:
644
+ FileUtils::OPT_TABLE.each do |name, opts|
645
+ default_options = []
646
+ if opts.include?(:verbose) || opts.include?("verbose")
647
+ default_options << ':verbose => RakeFileUtils.verbose_flag == true'
648
+ end
649
+ next if default_options.empty?
650
+ module_eval(<<-EOS, __FILE__, __LINE__ + 1)
651
+ def #{name}( *args, &block )
652
+ super(
653
+ *rake_merge_option(args,
654
+ #{default_options.join(', ')}
655
+ ), &block)
656
+ end
657
+ EOS
658
+ end
659
+ end