daddy 0.0.21 → 0.0.22

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NWRjNDQxMTAwNDZhOTg3MjRhZWNlOWVmNTFjNzNkNjg5NjU0MWNlNg==
4
+ ZDk2Mjg3NzBlMzkzN2U4ZDI5OTNhOWE5MzU1YTI4NDM3YjYxMmJiNQ==
5
5
  data.tar.gz: !binary |-
6
- NDFlNTIwZjUzODVjZTBkYTU2MTAwMGNmMDg2OTc4NjhkMjk3ZDQ2OA==
6
+ ZmI0N2RjMTgxZjNiYmZmMjYwMDFhNGI4MTFhY2VlOGMwNDA3ZWVlMQ==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- MDdmMTdmN2JmZGQ1ZTFlMTc0YjAzZWE1YzEzMTMyYTE4MjIxZGNkZDI0NWU3
10
- N2MwYzg0Y2Q4NzBiMDNkMzczOGRjYWYwYWVlOTI5MTZlNWE1ZmFjYmEyZjgy
11
- ZDk0Yjc2NzAwMDNjZDA5Njk0MzUyZTZlMWI4ZDBhYjczODMyZTI=
9
+ MWZmODNhMWVlODE3MDhhYTY0OTc3MTIxNmM3YzcxOWRlY2YyMDdhN2IzMzZh
10
+ NTk5MjkzYzExNzU5MjA4OWMwZDg0NWVmOWE1MGJmNzY3OTQ4MWQ1YjNjNmFm
11
+ ZDc2MWMxMDIzODg1ZGEwNjY3ODFkYWY4Y2Y1NDRlMTJhYjUxNjI=
12
12
  data.tar.gz: !binary |-
13
- ZjkwODIyZGYyMDA2NmEyODQ2ZjQ0NzI5ZWZiZDYxMTE4YzU0OWJiNTY2Mzhj
14
- YWI0YWIwY2VhZjUwZjA1YjA2NmNjYTcyMDVlNjJhNWUwODk5M2U5MDk5OGEx
15
- N2QxNzk5ODlkN2E4NDZmMDBiZTRkNTJmYTU3ZjA2ZDZlYTk0YmU=
13
+ ZWRkYmExNDc3ZDlkNWY1YjNlZjljYjgzYjQ3NTIzYTdjODI2NzZkZDJmOGNj
14
+ MzgyYjAzNmVlNmY1OTMyZDZhYzRkMjk1ZjM5YTVmNGMzOTI1YTEzYWE3NTM2
15
+ NGE3ODMyMWIwOGFlYTBjY2RkZjZjZjYzNDMxZmNjOTM5YzgwNTc=
@@ -25,7 +25,7 @@ module Daddy
25
25
 
26
26
  puts %{
27
27
  <div>#{url}</div>
28
- <img style="margin: 5px 0; background: #ffffff;" src="screenshots/#{image}"/>
28
+ <img class="screenshot" src="screenshots/#{image}"/>
29
29
  }
30
30
  end
31
31
  end
@@ -10,7 +10,7 @@ module Daddy
10
10
  b = git.show_previous(file, true).gsub(/[<>]/, '<' => '&lt;', '>' => '&gt;')
11
11
  diff = format_diff(Differ.diff(a, b))
12
12
 
13
- puts file
13
+ show_filename(file, options)
14
14
  puts "<pre>#{diff}</pre>"
15
15
  end
16
16
 
@@ -28,13 +28,21 @@ module Daddy
28
28
  puts "<pre>#{diff}</pre>"
29
29
  end
30
30
 
31
- def show(file)
32
- puts file
31
+ def show(file, options = {})
32
+ show_filename(file, options)
33
33
  puts "<pre>#{File.read(file).gsub(/[<>]/, '<' => '&lt;', '>' => '&gt;')}</pre>"
34
34
  end
35
35
 
36
36
  private
37
37
 
38
+ def show_filename(filename, options = {})
39
+ if options[:as] == 'new'
40
+ puts "<span class=\"new\">[新規作成] #{filename}</span>"
41
+ else
42
+ puts filename
43
+ end
44
+ end
45
+
38
46
  def format_diff(diff)
39
47
  lines = []
40
48
 
@@ -1,9 +1,4 @@
1
- .contents {
2
- margin-left: 100px;
3
- }
4
-
5
1
  #menu {
6
- width: 100px;
7
2
  float: left;
8
3
  background: #FFFFFF;
9
4
  color: #000000;
@@ -24,6 +19,7 @@
24
19
  vertical-align: middle;
25
20
  font-size: 1.2em;
26
21
  font-weight: bold;
22
+ white-space: nowrap;
27
23
  }
28
24
 
29
25
  #menu ol li.sub_menu {
@@ -90,6 +86,10 @@ div.background {
90
86
  margin-left: 20px;
91
87
  }
92
88
 
89
+ div.background ol {
90
+ margin-left: 20px;
91
+ }
92
+
93
93
  div.feature .narrative {
94
94
  margin-left: 10px;
95
95
  }
@@ -115,6 +115,11 @@ div.scenario td {
115
115
  padding: 5px;
116
116
  }
117
117
 
118
+ span.new {
119
+ color: #006400;
120
+ font-weight: bold;
121
+ }
122
+
118
123
  ins.differ {
119
124
  text-decoration: none;
120
125
  background: #90EE90;
@@ -124,3 +129,10 @@ del.differ {
124
129
  text-decoration: none;
125
130
  background: #FFB6C1;
126
131
  }
132
+
133
+ .screenshot {
134
+ border: solid 1px #999999;
135
+ border-radius: 5px 5px;
136
+ margin: 5px 0;
137
+ background: #ffffff;
138
+ }
@@ -15,7 +15,6 @@ module Daddy
15
15
  include Daddy::Formatter::DaddyHtml
16
16
 
17
17
  def initialize(runtime, path_or_io, options)
18
- @path_or_io = path_or_io
19
18
  @io = ensure_io(path_or_io, "html")
20
19
  @runtime = runtime
21
20
  @options = options
@@ -45,8 +44,9 @@ module Daddy
45
44
  end
46
45
  end
47
46
 
47
+
48
48
  def before_features(features)
49
- @step_count = get_step_count(features)
49
+ @step_count = features.step_count
50
50
 
51
51
  @builder.declare!(:DOCTYPE, :html)
52
52
  @builder << '<html>'
@@ -215,8 +215,6 @@ module Daddy
215
215
 
216
216
  lines = name.split("\n")
217
217
  @builder.h3(:id => "scenario_#{@scenario_number}") do
218
- @builder.span(keyword + ':', :class => 'keyword')
219
- @builder.text!(' ')
220
218
  @builder.span(lines[0], :class => 'val')
221
219
  end
222
220
 
@@ -262,7 +260,6 @@ module Daddy
262
260
  end
263
261
 
264
262
  def before_steps(steps)
265
- @step_count_in_scenario = steps.count
266
263
  @builder << '<ol style="display: none;">'
267
264
  end
268
265
 
@@ -399,7 +396,11 @@ module Daddy
399
396
  end
400
397
  end
401
398
  end
402
- set_scenario_color_failed
399
+ if table_row.exception.is_a? ::Cucumber::Pending
400
+ set_scenario_color_pending
401
+ else
402
+ set_scenario_color_failed
403
+ end
403
404
  end
404
405
  if @outline_row
405
406
  @outline_row += 1
@@ -497,8 +498,8 @@ module Daddy
497
498
  unless @header_red
498
499
  @builder.text!("makeRed('cucumber-header');")
499
500
  @builder.text!("makeMenuRed();")
500
- @header_red = true
501
501
  end
502
+ @header_red = true
502
503
  @builder.text!("makeRed('scenario_#{@scenario_number}');") unless @scenario_red
503
504
  @scenario_red = true
504
505
  end
@@ -514,52 +515,16 @@ module Daddy
514
515
  end
515
516
  end
516
517
 
517
- def get_step_count(features)
518
- count = 0
519
- features = features.instance_variable_get("@features")
520
- features.each do |feature|
521
- #get background steps
522
- if feature.instance_variable_get("@background")
523
- background = feature.instance_variable_get("@background")
524
- background.init
525
- background_steps = background.instance_variable_get("@steps").instance_variable_get("@steps")
526
- count += background_steps.size
527
- end
528
- #get scenarios
529
- feature.instance_variable_get("@feature_elements").each do |scenario|
530
- scenario.init
531
- #get steps
532
- steps = scenario.instance_variable_get("@steps").instance_variable_get("@steps")
533
- count += steps.size
534
-
535
- #get example table
536
- examples = scenario.instance_variable_get("@examples_array")
537
- unless examples.nil?
538
- examples.each do |example|
539
- example_matrix = example.instance_variable_get("@outline_table").instance_variable_get("@cell_matrix")
540
- count += example_matrix.size
541
- end
542
- end
543
-
544
- #get multiline step tables
545
- steps.each do |step|
546
- multi_arg = step.instance_variable_get("@multiline_arg")
547
- next if multi_arg.nil?
548
- matrix = multi_arg.instance_variable_get("@cell_matrix")
549
- count += matrix.size unless matrix.nil?
550
- end
551
- end
552
- end
553
- return count
554
- end
555
-
556
518
  def build_step(keyword, step_match, status)
557
519
  if @in_background
558
520
  display_keyword = keyword.strip + ' '
559
521
  else
560
522
  if keyword.strip == '*'
561
523
  @step_number_in_scenario += 1
562
- display_keyword = sprintf("%0#{@step_count_in_scenario.to_s.size}d", @step_number_in_scenario) + '. '
524
+ display_keyword = ''
525
+ display_keyword << '0' if @step_number_in_scenario.to_s.size == 1
526
+ display_keyword << @step_number_in_scenario.to_s
527
+ display_keyword << '. '
563
528
  else
564
529
  display_keyword = keyword.strip + ' '
565
530
  end
@@ -658,7 +623,6 @@ module Daddy
658
623
  $("#expander").click(function() {
659
624
  $(SCENARIOS).siblings().show();
660
625
  });
661
-
662
626
  })
663
627
 
664
628
  function moveProgressBar(percentDone) {
@@ -5,6 +5,8 @@
5
5
 
6
6
  <script>
7
7
  $(document).ready(function() {
8
+ $('.contents').css('margin-left', $('#menu').width());
9
+
8
10
  $('.sprint').mouseover(function() {
9
11
  $(this).css('background', '#F0F8FF').css('cursor', 'pointer');
10
12
  }).mouseout(function() {
@@ -25,13 +27,13 @@
25
27
  <%= title %>
26
28
  </li>
27
29
  <li class="sub_menu" style="display: none;">
28
- <a href="../<%= b %>/diary.html">開発日記</a>
30
+ <a href="../../<%= b %>/diary/index.html">開発日記</a>
29
31
  </li>
30
32
  <li class="sub_menu" style="display: none;">
31
- <a href="../<%= b %>/index.html">仕様書</a>
33
+ <a href="../../<%= b %>/spec/index.html">仕様書</a>
32
34
  </li>
33
35
  <li class="sub_menu" style="display: none;">
34
- <a href="../<%= b %>/coverage/rcov/index.html" target="_blank">カバレッジ</a>
36
+ <a href="../../<%= b %>/coverage/rcov/index.html" target="_blank">カバレッジ</a>
35
37
  </li>
36
38
  </ol>
37
39
  <% end %>
@@ -33,7 +33,11 @@ module Daddy
33
33
  elsif b == 'master' or b == 'remotes/origin/master'
34
34
  1
35
35
  else
36
- b <=> a
36
+ if remote
37
+ b.sub('remotes/origin/p', '').to_i <=> a.sub('remotes/origin/p', '').to_i
38
+ else
39
+ b.sub('p', '').to_i <=> a.sub('p', '').to_i
40
+ end
37
41
  end
38
42
  end
39
43
 
@@ -0,0 +1,16 @@
1
+ # coding: UTF-8
2
+
3
+ module Daddy
4
+ module Helpers
5
+
6
+ module HtmlHelper
7
+
8
+ def html_line_break(s)
9
+ ret = html_escape(s)
10
+ ret.gsub(/\r\n|\r|\n/, "<br/>").html_safe
11
+ end
12
+
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ # coding: UTF-8
2
+
3
+ module Daddy
4
+ class Model < Hash
5
+ extend ActiveModel::Naming
6
+ include ActiveModel::Conversion
7
+ include ActiveModel::Validations
8
+
9
+ def initialize(params = {})
10
+ self.merge!(params) if params
11
+ end
12
+
13
+ def persisted?
14
+ false
15
+ end
16
+
17
+ def method_missing(method, *params)
18
+ method_name = method.to_s
19
+ if method_name.last == "="
20
+ self[method_name[0..-2]] = params.first
21
+ else
22
+ self[method_name]
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,29 @@
1
+ # coding: UTF-8
2
+
3
+ require 'daddy/utils/sql_utils'
4
+
5
+ module Daddy
6
+ module Models
7
+
8
+ module ActsAsLike
9
+ module Mixin
10
+ def acts_as_like(options = {})
11
+ extend ClassMethods
12
+ include InstanceMethods
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+
18
+ def like(columns, keywords)
19
+ where(Daddy::Utils::SqlUtils.like(columns, keywords))
20
+ end
21
+
22
+ end
23
+
24
+ module InstanceMethods
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -16,6 +16,12 @@ if ENV["COVERAGE"]
16
16
  SimpleCov.start 'rails'
17
17
  end
18
18
 
19
+ require 'daddy/model'
20
+ require 'daddy/helpers/html_helper'
21
+ require 'daddy/models/acts_as_like'
22
+
23
+ Object.send :include, Daddy::Models::ActsAsLike::Mixin
24
+
19
25
  module Daddy
20
26
  class Railtie < Rails::Railtie
21
27
  rake_tasks do
@@ -0,0 +1,38 @@
1
+ # coding: UTF-8
2
+
3
+ module Daddy
4
+ module Utils
5
+ class SqlUtils
6
+
7
+ def self.escape_search(str)
8
+ str.gsub(/\\/, '\\\\\\\\').gsub(/%/, '\%').gsub(/_/, '\_')
9
+ end
10
+
11
+ def self.like(columns, keywords)
12
+ target_columns = columns.is_a?(Array) ? columns : [columns]
13
+
14
+ sql = []
15
+ sql[0] = '('
16
+
17
+ keywords.gsub(/ /, ' ').split.each_with_index do |s, i|
18
+ like = SqlUtils.escape_search(s)
19
+
20
+ sql[0] << ' or ' if i > 0
21
+ sql[0] << '('
22
+
23
+ target_columns.each_with_index do |column, j|
24
+ sql[0] << ' or ' if j > 0
25
+ sql[0] << "#{column} like ?"
26
+ sql << '%' + like + '%'
27
+ end
28
+
29
+ sql[0] << ')'
30
+ end
31
+
32
+ sql[0] << ')'
33
+ sql
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -19,13 +19,12 @@ namespace :dad do
19
19
  features << arg unless arg.index('=')
20
20
  end
21
21
 
22
- output_file = ENV['OUTPUT_FILE']
23
- output_file ||= 'index.html' if format == 'Daddy::Formatter::Html'
24
-
25
- output = "> features/reports/#{output_file}" if output_file
22
+ output = "> features/reports/index.html"
26
23
  output = "-o features/reports" if format == 'junit'
27
24
 
28
- ret = system("bundle exec cucumber --guess -r features -f #{format} #{options} #{features.join(' ')} #{output}")
29
- fail unless ret
25
+ command = "bundle exec cucumber --guess -r features -f #{format} #{features.join(' ')} #{options} #{output}"
26
+ #puts command
27
+ ret = system(command)
28
+ fail unless ret
30
29
  end
31
30
  end
@@ -4,30 +4,33 @@ require 'rake'
4
4
 
5
5
  namespace :dad do
6
6
 
7
- desc '本日用の日記を準備します。'
7
+ desc '開発日記を実行します。'
8
8
  task :diary do
9
- today = Date.today.strftime('%Y-%m-%d')
10
-
11
- system("rake dad:cucumber:install")
12
-
13
- today = Date.today.strftime('%Y-%m-%d')
14
-
15
- feature = "features/開発日記/#{today}.feature"
16
- if File.exist?(feature)
17
- puts "すでに #{feature} が存在します。上書きはしません。"
18
- else
19
- system("echo '# language: ja' > #{feature}")
20
- system("echo >> #{feature}")
21
- system("echo '機能:' >> #{feature}")
22
- system("echo >> #{feature}")
23
- end
24
-
25
- step = "features/step_definitions/開発日記/#{today}.rb"
26
- if File.exist?(step)
27
- puts "すでに #{step} が存在します。上書きはしません。"
28
- else
29
- system("echo '# coding: UTF-8' > #{step}")
30
- system("echo >> #{step}")
9
+ system("bundle exec rake dad:cucumber features/開発日記")
10
+ end
11
+
12
+ namespace :diary do
13
+ desc '本日用の開発日記を準備します。'
14
+ task :new do
15
+ today = Date.today.strftime('%Y-%m-%d')
16
+
17
+ system("rake dad:cucumber:install")
18
+
19
+ today = Date.today.strftime('%Y-%m-%d')
20
+
21
+ feature = "features/開発日記/#{today}.feature"
22
+ unless File.exist?(feature)
23
+ system("echo '# language: ja' > #{feature}")
24
+ system("echo >> #{feature}")
25
+ system("echo '機能:' >> #{feature}")
26
+ system("echo >> #{feature}")
27
+ end
28
+
29
+ step = "features/step_definitions/開発日記/#{today}.rb"
30
+ unless File.exist?(step)
31
+ system("echo '# coding: UTF-8' > #{step}")
32
+ system("echo >> #{step}")
33
+ end
31
34
  end
32
35
  end
33
36
  end
@@ -19,6 +19,7 @@ server {
19
19
  proxy_pass http://unicorn;
20
20
  }
21
21
 
22
+ <% if ENV['RAILS_ENV'] == 'production' %>
22
23
  location ~ ^/(assets)/ {
23
24
  gzip_vary on;
24
25
  gzip_static on;
@@ -26,7 +27,7 @@ server {
26
27
  add_header Cache-Control public;
27
28
  add_header ETag "";
28
29
  }
29
-
30
+ <% end -%>
30
31
  <% if ENV['JENKINS'].to_s.downcase == 'true' %>
31
32
  location /jenkins/ {
32
33
  root /var/cache/jenkins/war;
@@ -36,7 +37,6 @@ server {
36
37
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
37
38
  }
38
39
  <% end -%>
39
-
40
40
  <% if ENV['PUBLISH'].to_s.downcase == 'true' %>
41
41
  location /spec/ {
42
42
  root /var/lib/daddy;
@@ -6,7 +6,7 @@ namespace :dad do
6
6
  namespace :nginx do
7
7
 
8
8
  desc 'Nginxをインストールします。'
9
- task :install do
9
+ task :install => :environment do
10
10
  repo = File.dirname(__FILE__) + '/nginx.repo'
11
11
  ret = system("sudo cp -f #{repo} /etc/yum.repos.d/")
12
12
  fail unless ret
@@ -25,7 +25,7 @@ namespace :dad do
25
25
  jenkins = ENV['JENKINS'] || false
26
26
  publish = ENV['PUBLISH'] || false
27
27
 
28
- ret = system("RAILS_ROOT=#{rails_root} erb -T - #{File.dirname(__FILE__)}/nginx.conf.erb > tmp/nginx.conf")
28
+ ret = system("RAILS_ROOT=#{rails_root} RAILS_ENV=#{Rails.env} erb -T - #{File.dirname(__FILE__)}/nginx.conf.erb > tmp/nginx.conf")
29
29
  fail unless ret
30
30
  system("sudo cp -f tmp/nginx.conf /etc/nginx/conf.d/nginx.conf")
31
31
 
@@ -9,8 +9,16 @@ namespace :dad do
9
9
  fail unless ret
10
10
  end
11
11
 
12
- system("bundle exec rake dad:cucumber PUBLISH=true EXPAND=false OUTPUT_FILE=diary.html features/開発日記")
13
- system("bundle exec rake dad:cucumber PUBLISH=true EXPAND=false OUTPUT_FILE=index.html features/仕様書")
12
+ system("mkdir -p features/reports")
13
+ system("rm -Rf features/reports/*")
14
+ system("bundle exec rake dad:cucumber PUBLISH=true EXPAND=false features/開発日記")
15
+ system("mkdir -p features/reports/diary")
16
+ system("mv features/reports/index.html features/reports/diary")
17
+ system("mv features/reports/screenshots features/reports/diary")
18
+ system("bundle exec rake dad:cucumber PUBLISH=true EXPAND=false features/仕様書")
19
+ system("mkdir -p features/reports/spec")
20
+ system("mv features/reports/index.html features/reports/spec")
21
+ system("mv features/reports/screenshots features/reports/spec")
14
22
 
15
23
  if ENV['BRANCH']
16
24
  current_branch = ENV['BRANCH']
@@ -24,11 +32,8 @@ namespace :dad do
24
32
  system("sudo chown -R #{ENV['USER']}:#{ENV['USER']} #{dir}")
25
33
 
26
34
  system("mkdir -p #{dir}/#{current_branch}")
27
-
28
- system("rm -Rf #{dir}/#{current_branch}/screenshots")
35
+ system("rm -Rf #{dir}/#{current_branch}/*")
29
36
  system("cp -Rf features/reports/* #{dir}/#{current_branch}/")
30
-
31
- system("rm -Rf #{dir}/#{current_branch}/coverage")
32
37
  system("cp -Rf coverage #{dir}/#{current_branch}/")
33
38
  end
34
39
 
@@ -9,7 +9,10 @@ namespace :dad do
9
9
  system("mkdir -p features/reports")
10
10
  system("rm -Rf features/reports/*")
11
11
 
12
- ret = system("bundle exec rake dad:cucumber #{ARGV[1..-1].join(' ')}")
12
+ args = ARGV[1..-1].join(' ')
13
+ command = "bundle exec rake dad:cucumber #{args}"
14
+ #puts command
15
+ ret = system(command)
13
16
  fail unless ret
14
17
  end
15
18
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: daddy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.21
4
+ version: 0.0.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - ichy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-04-09 00:00:00.000000000 Z
11
+ date: 2013-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capybara
@@ -164,7 +164,7 @@ dependencies:
164
164
  - - ! '>='
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
- description: Dadday helps me build rails applications since daddy knows some best
167
+ description: Dadday helps me build rails applications since daddy knows some good
168
168
  practices.
169
169
  email: ichylinux@gmail.com
170
170
  executables: []
@@ -180,8 +180,10 @@ files:
180
180
  - lib/daddy/cucumber/assert.rb
181
181
  - lib/daddy/cucumber/table.rb
182
182
  - lib/daddy/cucumber/diff.rb
183
+ - lib/daddy/helpers/html_helper.rb
183
184
  - lib/daddy/capistrano/remote_cache_subdir.rb
184
185
  - lib/daddy/git.rb
186
+ - lib/daddy/model.rb
185
187
  - lib/daddy/formatter/menu.html.erb
186
188
  - lib/daddy/formatter/html.rb
187
189
  - lib/daddy/formatter/daddy_html.rb
@@ -189,6 +191,8 @@ files:
189
191
  - lib/daddy/formatter/cucumber.css
190
192
  - lib/daddy/formatter/jquery-min.js
191
193
  - lib/daddy/railtie.rb
194
+ - lib/daddy/models/acts_as_like.rb
195
+ - lib/daddy/utils/sql_utils.rb
192
196
  - lib/tasks/jenkins
193
197
  - lib/tasks/nginx.repo
194
198
  - lib/tasks/unicorn.rb