marginalia 1.6.0 → 1.10.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: bda214f48d77afb13f9c9182a550272d4e654c4f
4
- data.tar.gz: 5d199a1edd3a808254824a2bb45e22deca536e22
2
+ SHA256:
3
+ metadata.gz: d87c1e1a9f2c0653a979e4bc598c686c8fb7e7af4281f6571c915cb76eee2742
4
+ data.tar.gz: 18b9c7227dc0fedf7fc74954023274484a79a30fe8d9cc47d09c6ecb46010538
5
5
  SHA512:
6
- metadata.gz: 7f7ee0ed6593d2a639c31787a559a86db0367b63ed79dde39966a4264904bbbd77d822e01be212ae40e7a573330281cb75489fc08e577c28e4d059712bcd2a86
7
- data.tar.gz: 4963089d9d9609fd5dbdae17c36e6ed001cea24b81550febdf0826fc3fe13d574f34c8bb51a1ffc6b270e30ba68dd6c14b3d693cec8fcc6bfa4370d8fdee144a
6
+ metadata.gz: 88df0c3b95e116f53a63f6acb1dd6ba63baba048b11e09b47e723d394588c20bab9fadd7035da5a5183fa120fc6871dc2d04205f6397744669f564f684a9f8d5
7
+ data.tar.gz: d91e987e20e1d6a9c257cd5c68b2251b3ced7194f20c38b35e28711088ad030823b0f7018667ce5cb9e02015f472c0fe0a0a34d4ff614dac38194f78e191327b
@@ -1 +1 @@
1
- 2.2.3
1
+ 2.6.6
@@ -1,18 +1,34 @@
1
1
  language: ruby
2
+ sudo: false
3
+
4
+ services:
5
+ - mysql
6
+ - postgresql
2
7
 
3
8
  rvm:
4
- - 2.3.1
5
- - 2.4.4
6
- - 2.5.1
9
+ - 2.2
10
+ - 2.3
11
+ - 2.4
12
+ - 2.5
13
+ - 2.6
14
+ - 2.7
7
15
 
8
- sudo: false
16
+ services:
17
+ - mysql
18
+ - postgresql
19
+
20
+ script: "bundle exec rake db:reset test:all"
9
21
 
10
- script: bundle exec rake db:reset test:all
22
+ gemfile:
23
+ - gemfiles/4.2.gemfile
24
+ - gemfiles/4.2.api.gemfile
25
+ - gemfiles/5.0.gemfile
26
+ - gemfiles/5.1.gemfile
27
+ - gemfiles/5.2.gemfile
11
28
 
12
- env:
13
- - "RAILS_VERSION=4.2.0"
14
- - "RAILS_VERSION=5.0.6"
15
- - "RAILS_VERSION=5.1.5"
16
- - "RAILS_VERSION=4.2.0 TEST_RAILS_API=true"
17
- - "RAILS_VERSION=5.0.6 TEST_RAILS_API=true"
18
- - "RAILS_VERSION=5.1.5 TEST_RAILS_API=true"
29
+ matrix:
30
+ exclude:
31
+ - rvm: 2.7
32
+ gemfile: gemfiles/4.2.gemfile
33
+ - rvm: 2.7
34
+ gemfile: gemfiles/4.2.api.gemfile
data/Gemfile CHANGED
@@ -10,7 +10,7 @@ else
10
10
  gem 'mysql2', '>= 0.3.13', '< 0.5'
11
11
  end
12
12
  gem 'pg', '~> 0.15'
13
- gem 'sqlite3'
13
+ gem 'sqlite3', '~> 1.3.6'
14
14
 
15
15
  rails = case version
16
16
  when "master"
@@ -24,3 +24,7 @@ gem "rails", rails
24
24
  if ENV["TEST_RAILS_API"] == "true"
25
25
  gem "rails-api", "~> 0.2.1"
26
26
  end
27
+
28
+ if RUBY_VERSION.start_with?('2.3')
29
+ gem 'mysql'
30
+ end
data/README.md CHANGED
@@ -56,6 +56,8 @@ Optionally, you can set the application name shown in the log like so in an init
56
56
  For Rails 3 applications, the name will default to your Rails application name.
57
57
  For Rails 2 applications, "rails" is used as the default application name.
58
58
 
59
+ #### Components
60
+
59
61
  You can also configure the components of the comment that will be appended,
60
62
  by setting `Marginalia::Comment.components`. By default, this is set to:
61
63
 
@@ -100,6 +102,37 @@ With ActiveRecord >= 3.2.19:
100
102
 
101
103
  Pull requests for other included comment components are welcome.
102
104
 
105
+ #### Prepend comments
106
+
107
+ By default marginalia appends the comments at the end of the query. Certain databases, such as MySQL will truncate
108
+ the query text. This is the case for slow query logs and the results of querying some InnoDB internal tables where the
109
+ length of the query is more than 1024 bytes.
110
+
111
+ In order to not lose the marginalia comments from your logs, you can prepend the comments using this option:
112
+
113
+ Marginalia::Comment.prepend_comment = true
114
+
115
+ #### Inline query annotations
116
+
117
+ In addition to the request or job-level component-based annotations,
118
+ Marginalia may be used to add inline annotations to specific queries using a
119
+ block-based API.
120
+
121
+ For example, the following code:
122
+
123
+ Marginalia.with_annotation("foo") do
124
+ Account.where(queenbee_id: 1234567890).first
125
+ end
126
+
127
+ will issue this query:
128
+
129
+ Account Load (0.3ms) SELECT `accounts`.* FROM `accounts`
130
+ WHERE `accounts`.`queenbee_id` = 1234567890
131
+ LIMIT 1
132
+ /*application:BCX,controller:project_imports,action:show*/ /*foo*/
133
+
134
+ Nesting `with_annotation` blocks will concatenate the comment strings.
135
+
103
136
  ## Contributing
104
137
 
105
138
  Start by bundling and creating the test database:
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "mysql2", "~> 0.3.13"
4
+ gem "pg", "~> 0.15"
5
+ gem "sqlite3", "~> 1.3.6"
6
+ gem "rails", "= 4.2.11.1"
7
+ gem "rails-api", "~> 0.2.1"
8
+
9
+ gemspec :path => "../"
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "mysql2", "~> 0.3.13"
4
+ gem "pg", "~> 0.15"
5
+ gem "sqlite3", "~> 1.3.6"
6
+ gem "rails", "= 4.2.11.1"
7
+
8
+ gemspec :path => "../"
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "mysql2", "~> 0.3.13"
4
+ gem "pg", "~> 0.15"
5
+ gem "sqlite3", "~> 1.3.6"
6
+ gem "rails", "= 5.0.7.2"
7
+
8
+ gemspec :path => "../"
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "mysql2", "~> 0.3.13"
4
+ gem "pg", "~> 0.15"
5
+ gem "sqlite3", "~> 1.3.6"
6
+ gem "rails", "= 5.1.6.2"
7
+
8
+ gemspec :path => "../"
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "mysql2", "~> 0.4.10"
4
+ gem "pg", "~> 0.15"
5
+ gem "sqlite3", "~> 1.3.6"
6
+ gem "rails", "= 5.2.2.1"
7
+
8
+ gemspec :path => "../"
@@ -1,5 +1,6 @@
1
1
  require 'marginalia/railtie'
2
2
  require 'marginalia/comment'
3
+ require 'marginalia/sidekiq_instrumentation'
3
4
 
4
5
  module Marginalia
5
6
  mattr_accessor :application_name
@@ -48,10 +49,22 @@ module Marginalia
48
49
  Marginalia::Comment.update_adapter!(self)
49
50
  comment = Marginalia::Comment.construct_comment
50
51
  if comment.present? && !sql.include?(comment)
51
- "#{sql} /*#{comment}*/"
52
- else
53
- sql
52
+ sql = if Marginalia::Comment.prepend_comment
53
+ "/*#{comment}*/ #{sql}"
54
+ else
55
+ "#{sql} /*#{comment}*/"
56
+ end
57
+ end
58
+ inline_comment = Marginalia::Comment.construct_inline_comment
59
+ if inline_comment.present? && !sql.include?(inline_comment)
60
+ sql = if Marginalia::Comment.prepend_comment
61
+ "/*#{inline_comment}*/ #{sql}"
62
+ else
63
+ "#{sql} /*#{inline_comment}*/"
64
+ end
54
65
  end
66
+
67
+ sql
55
68
  end
56
69
 
57
70
  def execute_with_marginalia(sql, name = nil)
@@ -63,9 +76,9 @@ module Marginalia
63
76
  end
64
77
 
65
78
  if ActiveRecord::VERSION::MAJOR >= 5
66
- def exec_query_with_marginalia(sql, name = 'SQL', binds = [], options = {})
79
+ def exec_query_with_marginalia(sql, name = 'SQL', binds = [], **options)
67
80
  options[:prepare] ||= false
68
- exec_query_without_marginalia(annotate_sql(sql), name, binds, options)
81
+ exec_query_without_marginalia(annotate_sql(sql), name, binds, **options)
69
82
  end
70
83
  end
71
84
 
@@ -77,9 +90,15 @@ module Marginalia
77
90
  exec_update_without_marginalia(annotate_sql(sql), name, binds)
78
91
  end
79
92
 
80
- def execute_and_clear_with_marginalia(sql, *args, &block)
81
- execute_and_clear_without_marginalia(annotate_sql(sql), *args, &block)
93
+ if ActiveRecord::VERSION::MAJOR >= 5
94
+ def execute_and_clear_with_marginalia(sql, *args, **kwargs, &block)
95
+ execute_and_clear_without_marginalia(annotate_sql(sql), *args, **kwargs, &block)
82
96
  end
97
+ else
98
+ def execute_and_clear_with_marginalia(sql, *args, &block)
99
+ execute_and_clear_without_marginalia(annotate_sql(sql), *args, &block)
100
+ end
101
+ end
83
102
  end
84
103
 
85
104
  module ActionControllerInstrumentation
@@ -100,4 +119,11 @@ module Marginalia
100
119
  Marginalia::Comment.clear!
101
120
  end
102
121
  end
122
+
123
+ def self.with_annotation(comment, &block)
124
+ Marginalia::Comment.inline_annotations.push(comment)
125
+ block.call if block.present?
126
+ ensure
127
+ Marginalia::Comment.inline_annotations.pop
128
+ end
103
129
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'socket'
2
4
 
3
5
  module Marginalia
4
6
  module Comment
5
- mattr_accessor :components, :lines_to_ignore
7
+ mattr_accessor :components, :lines_to_ignore, :prepend_comment
6
8
  Marginalia::Comment.components ||= [:application, :controller, :action]
7
9
 
8
10
  def self.update!(controller = nil)
@@ -18,11 +20,11 @@ module Marginalia
18
20
  end
19
21
 
20
22
  def self.construct_comment
21
- ret = ''
23
+ ret = String.new
22
24
  self.components.each do |c|
23
25
  component_value = self.send(c)
24
26
  if component_value.present?
25
- ret << "#{c.to_s}:#{component_value.to_s},"
27
+ ret << "#{c}:#{component_value},"
26
28
  end
27
29
  end
28
30
  ret.chop!
@@ -30,6 +32,11 @@ module Marginalia
30
32
  ret
31
33
  end
32
34
 
35
+ def self.construct_inline_comment
36
+ return nil if inline_annotations.none?
37
+ escape_sql_comment(inline_annotations.join)
38
+ end
39
+
33
40
  def self.escape_sql_comment(str)
34
41
  while str.include?('/*') || str.include?('*/')
35
42
  str = str.gsub('/*', '').gsub('*/', '')
@@ -96,8 +103,15 @@ module Marginalia
96
103
  marginalia_controller.action_name if marginalia_controller.respond_to? :action_name
97
104
  end
98
105
 
106
+ def self.sidekiq_job
107
+ marginalia_job["class"] if marginalia_job && marginalia_job.respond_to?(:[])
108
+ end
109
+
110
+ DEFAULT_LINES_TO_IGNORE_REGEX = %r{\.rvm|/ruby/gems/|vendor/|marginalia|rbenv|monitor\.rb.*mon_synchronize}
111
+
99
112
  def self.line
100
- Marginalia::Comment.lines_to_ignore ||= /\.rvm|gem|vendor\/|marginalia|rbenv/
113
+ Marginalia::Comment.lines_to_ignore ||= DEFAULT_LINES_TO_IGNORE_REGEX
114
+
101
115
  last_line = caller.detect do |line|
102
116
  line !~ Marginalia::Comment.lines_to_ignore
103
117
  end
@@ -154,6 +168,10 @@ module Marginalia
154
168
  marginalia_adapter.pool.spec.config
155
169
  end
156
170
  end
171
+
172
+ def self.inline_annotations
173
+ Thread.current[:marginalia_inline_annotations] ||= []
174
+ end
157
175
  end
158
176
 
159
177
  end
@@ -0,0 +1,25 @@
1
+ module Marginalia
2
+
3
+ # Alternative to ActiveJob Instrumentation for Sidekiq.
4
+ # Apt for Instrumenting Sidekiq with Rails version < 4.2.
5
+ module SidekiqInstrumentation
6
+
7
+ class Middleware
8
+ def call(worker, msg, queue)
9
+ Marginalia::Comment.update_job! msg
10
+ yield
11
+ ensure
12
+ Marginalia::Comment.clear_job!
13
+ end
14
+ end
15
+
16
+ def self.enable!
17
+ Sidekiq.configure_server do |config|
18
+ config.server_middleware do |chain|
19
+ chain.add Marginalia::SidekiqInstrumentation::Middleware
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.authors = ["Noah Lorang", "Nick Quaranto", "Taylor Weibley"]
3
- gem.email = ["noah@37signals.com", "arthurnn@github.com"]
3
+ gem.email = ["arthurnn@github.com"]
4
4
  gem.homepage = "https://github.com/basecamp/marginalia"
5
5
 
6
6
  gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
@@ -8,7 +8,7 @@ Gem::Specification.new do |gem|
8
8
  gem.test_files = `git ls-files -- {test}/*`.split("\n")
9
9
  gem.name = "marginalia"
10
10
  gem.require_paths = ["lib"]
11
- gem.version = "1.6.0"
11
+ gem.version = "1.10.0"
12
12
  gem.license = "MIT"
13
13
 
14
14
  gem.add_runtime_dependency "actionpack", ">= 2.3"
@@ -19,8 +19,7 @@ Gem::Specification.new do |gem|
19
19
  gem.add_development_dependency "sqlite3"
20
20
  gem.add_development_dependency "minitest"
21
21
  gem.add_development_dependency "mocha"
22
+ gem.add_development_dependency "sidekiq"
22
23
 
23
24
  gem.summary = gem.description = %q{Attach comments to your ActiveRecord queries.}
24
-
25
- gem.extensions = ["ext/mkrf_conf.rb"]
26
25
  end
@@ -23,6 +23,8 @@ require 'logger'
23
23
  require 'pp'
24
24
  require 'active_record'
25
25
  require 'action_controller'
26
+ require 'sidekiq'
27
+ require 'sidekiq/testing'
26
28
 
27
29
  if request_id_available?
28
30
  require 'action_dispatch/middleware/request_id'
@@ -87,6 +89,13 @@ if active_job_available?
87
89
  end
88
90
  end
89
91
 
92
+ class PostsSidekiqJob
93
+ include Sidekiq::Worker
94
+ def perform
95
+ Post.first
96
+ end
97
+ end
98
+
90
99
  if using_rails_api?
91
100
  class PostsApiController < ActionController::API
92
101
  def driver_only
@@ -112,6 +121,7 @@ class MarginaliaTest < MiniTest::Test
112
121
  @queries << args.last[:sql]
113
122
  end
114
123
  @env = Rack::MockRequest.env_for('/')
124
+ ActiveJob::Base.queue_adapter = :inline
115
125
  end
116
126
 
117
127
  def test_double_annotate
@@ -206,6 +216,16 @@ class MarginaliaTest < MiniTest::Test
206
216
  assert_match %r{/\*line:.*lib/marginalia/comment.rb:[0-9]+}, @queries.first
207
217
  end
208
218
 
219
+ def test_default_lines_to_ignore_regex
220
+ line = "/gems/a_gem/lib/a_gem.rb:1:in `some_method'"
221
+ call_stack = [line] + caller
222
+
223
+ assert_match(
224
+ call_stack.detect { |line| line !~ Marginalia::Comment::DEFAULT_LINES_TO_IGNORE_REGEX },
225
+ line
226
+ )
227
+ end
228
+
209
229
  def test_hostname_and_pid
210
230
  Marginalia::Comment.components = [:hostname, :pid]
211
231
  PostsController.action(:driver_only).call(@env)
@@ -273,6 +293,33 @@ class MarginaliaTest < MiniTest::Test
273
293
  Post.first
274
294
  refute_match %{job:PostsJob}, @queries.last
275
295
  end
296
+
297
+ def test_active_job_with_sidekiq
298
+ Marginalia::Comment.components = [:job, :sidekiq_job]
299
+ PostsJob.perform_later
300
+ assert_match %{job:PostsJob}, @queries.first
301
+
302
+ Post.first
303
+ refute_match %{job:PostsJob}, @queries.last
304
+ end
305
+ end
306
+
307
+ def test_sidekiq_job
308
+ Marginalia::Comment.components = [:sidekiq_job]
309
+ Marginalia::SidekiqInstrumentation.enable!
310
+
311
+ # Test harness does not run Sidekiq middlewares by default so include testing middleware.
312
+ Sidekiq::Testing.server_middleware do |chain|
313
+ chain.add Marginalia::SidekiqInstrumentation::Middleware
314
+ end
315
+
316
+ Sidekiq::Testing.fake!
317
+ PostsSidekiqJob.perform_async
318
+ PostsSidekiqJob.drain
319
+ assert_match %{sidekiq_job:PostsSidekiqJob}, @queries.first
320
+
321
+ Post.first
322
+ refute_match %{sidekiq_job:PostsSidekiqJob}, @queries.last
276
323
  end
277
324
 
278
325
  def test_good_comment
@@ -284,6 +331,53 @@ class MarginaliaTest < MiniTest::Test
284
331
  assert_equal Marginalia::Comment.escape_sql_comment('**//; DROP TABLE USERS;/*'), '; DROP TABLE USERS;'
285
332
  end
286
333
 
334
+ def test_inline_annotations
335
+ Marginalia.with_annotation("foo") do
336
+ Post.first
337
+ end
338
+ Post.first
339
+ assert_match %r{/\*foo\*/$}, @queries.first
340
+ refute_match %r{/\*foo\*/$}, @queries.last
341
+ # Assert we're not adding an empty comment, either
342
+ refute_match %r{/\*\s*\*/$}, @queries.last
343
+ end
344
+
345
+ def test_nested_inline_annotations
346
+ Marginalia.with_annotation("foo") do
347
+ Marginalia.with_annotation("bar") do
348
+ Post.first
349
+ end
350
+ end
351
+ assert_match %r{/\*foobar\*/$}, @queries.first
352
+ end
353
+
354
+ def test_bad_inline_annotations
355
+ Marginalia.with_annotation("*/; DROP TABLE USERS;/*") do
356
+ Post.first
357
+ end
358
+ Marginalia.with_annotation("**//; DROP TABLE USERS;//**") do
359
+ Post.first
360
+ end
361
+ assert_match %r{/\*; DROP TABLE USERS;\*/$}, @queries.first
362
+ assert_match %r{/\*; DROP TABLE USERS;\*/$}, @queries.last
363
+ end
364
+
365
+ def test_inline_annotations_are_deduped
366
+ Marginalia.with_annotation("foo") do
367
+ ActiveRecord::Base.connection.execute "select id from posts /*foo*/"
368
+ end
369
+ assert_match %r{select id from posts /\*foo\*/ /\*application:rails\*/$}, @queries.first
370
+ end
371
+
372
+ def test_add_comments_to_beginning_of_query
373
+ Marginalia::Comment.prepend_comment = true
374
+
375
+ ActiveRecord::Base.connection.execute "select id from posts"
376
+ assert_match %r{/\*application:rails\*/ select id from posts$}, @queries.first
377
+ ensure
378
+ Marginalia::Comment.prepend_comment = nil
379
+ end
380
+
287
381
  def teardown
288
382
  Marginalia.application_name = nil
289
383
  Marginalia::Comment.lines_to_ignore = nil
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: marginalia
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Noah Lorang
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2018-09-24 00:00:00.000000000 Z
13
+ date: 2021-01-04 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: actionpack
@@ -124,13 +124,25 @@ dependencies:
124
124
  - - ">="
125
125
  - !ruby/object:Gem::Version
126
126
  version: '0'
127
+ - !ruby/object:Gem::Dependency
128
+ name: sidekiq
129
+ requirement: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
127
141
  description: Attach comments to your ActiveRecord queries.
128
142
  email:
129
- - noah@37signals.com
130
143
  - arthurnn@github.com
131
144
  executables: []
132
- extensions:
133
- - ext/mkrf_conf.rb
145
+ extensions: []
134
146
  extra_rdoc_files: []
135
147
  files:
136
148
  - ".gitignore"
@@ -140,11 +152,16 @@ files:
140
152
  - LICENSE
141
153
  - README.md
142
154
  - Rakefile
143
- - ext/mkrf_conf.rb
155
+ - gemfiles/4.2.api.gemfile
156
+ - gemfiles/4.2.gemfile
157
+ - gemfiles/5.0.gemfile
158
+ - gemfiles/5.1.gemfile
159
+ - gemfiles/5.2.gemfile
144
160
  - init.rb
145
161
  - lib/marginalia.rb
146
162
  - lib/marginalia/comment.rb
147
163
  - lib/marginalia/railtie.rb
164
+ - lib/marginalia/sidekiq_instrumentation.rb
148
165
  - marginalia.gemspec
149
166
  - test/query_comments_test.rb
150
167
  homepage: https://github.com/basecamp/marginalia
@@ -166,8 +183,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
183
  - !ruby/object:Gem::Version
167
184
  version: '0'
168
185
  requirements: []
169
- rubyforge_project:
170
- rubygems_version: 2.4.5.1
186
+ rubygems_version: 3.0.3
171
187
  signing_key:
172
188
  specification_version: 4
173
189
  summary: Attach comments to your ActiveRecord queries.
@@ -1,21 +0,0 @@
1
- require 'rubygems'
2
- require 'rubygems/command.rb'
3
- require 'rubygems/dependency_installer.rb'
4
-
5
- begin
6
- Gem::Command.build_args = ARGV
7
- rescue NoMethodError
8
- end
9
-
10
- installer = Gem::DependencyInstaller.new
11
- begin
12
- if RUBY_VERSION < "2.4"
13
- installer.install "mysql", ">=0"
14
- end
15
- rescue
16
- exit(1)
17
- end
18
-
19
- f = File.open(File.join(File.dirname(__FILE__), "Rakefile"), "w")
20
- f.write("task :default\n")
21
- f.close