bently 0.0.0 → 0.1.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.
@@ -0,0 +1,79 @@
1
+ module Bently
2
+
3
+ class HerokuResque < RailsRecipe
4
+
5
+ step :shell, 'echo', :description => "WARNING:\nSome steps in this recipe may incur fees to your Heroku account. By proceeding you agree to bear full responsibility for fees charged to you as a result.", :action => 'proceed', :fail_on_skip => true
6
+ step :add_gem, "gem 'resque', \"~> 1.22.0\""
7
+ step :shell, 'bundle install'
8
+ step :append, :file => 'Procfile', :with => 'resque: env TERM_CHILD=1 bundle exec rake jobs:work'
9
+ step :touch_rakefile
10
+ step :touch_sample_worker
11
+ step :prepend, :file => 'config/routes.rb', :with => "require 'resque/server'"
12
+ step :mount_resque_server
13
+ step :shell, "heroku addons:add redistogo:nano"
14
+ step :shell, 'heroku config | grep REDISTOGO_URL'
15
+ step :touch_resque_initializer
16
+ step :shell, 'echo REDISTOGO_URL=redis://localhost:6379 >> .env;more .env'
17
+ step :shell, 'heroku ps:scale resque=1'
18
+
19
+ protected
20
+
21
+ def touch_rakefile
22
+ touch(
23
+ :file => "./lib/tasks/resque.rake",
24
+ :with => rakefile
25
+ )
26
+ end
27
+
28
+ def rakefile
29
+ %{require 'resque/tasks'
30
+
31
+ task "resque:setup" => :environment do
32
+ ENV['QUEUE'] = '*'
33
+ end
34
+
35
+ desc "Alias for resque:work (To run workers on Heroku)"
36
+ task "jobs:work" => "resque:work"}
37
+ end
38
+
39
+ def touch_sample_worker
40
+ touch(
41
+ :file => './app/workers/sample_worker.rb',
42
+ :with => sample_worker
43
+ )
44
+ end
45
+
46
+ def sample_worker
47
+ %{# class SampleWorker
48
+ # @queue = :sample
49
+ #
50
+ # def self.perform(resource_id)
51
+ # resource = Resource.find(resource_id)
52
+ # resource.do_something!
53
+ # end
54
+ # end}
55
+ end
56
+
57
+ def mount_resque_server
58
+ insert(
59
+ :file => 'config/routes.rb',
60
+ :with => " mount Resque::Server.new, :at => \"/resque\"\n",
61
+ :after => "Application.routes.draw do\n"
62
+ )
63
+ end
64
+
65
+ def touch_resque_initializer
66
+ touch :file => 'config/initializers/resque.rb', :with => resque_initializer
67
+ end
68
+
69
+ def resque_initializer
70
+ %{# don't initialize unless ENV hash is present
71
+ if ENV["REDISTOGO_URL"].present?
72
+ uri = URI.parse(ENV["REDISTOGO_URL"])
73
+ Resque.redis = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
74
+ end}
75
+ end
76
+
77
+ end
78
+
79
+ end
@@ -0,0 +1,37 @@
1
+ module Bently
2
+
3
+ class HerokuSendgrid < RailsRecipe
4
+
5
+ step :heroku, 'addons:add sendgrid:starter'
6
+ step :touch_mail_initializer
7
+
8
+ protected
9
+
10
+ def heroku command
11
+ shell("heroku #{command}")
12
+ end
13
+
14
+ def touch_mail_initializer
15
+ touch(
16
+ :file => "./config/initializers/mail.rb",
17
+ :with => mail_initializer
18
+ )
19
+ end
20
+
21
+ def mail_initializer
22
+ %{
23
+ ActionMailer::Base.smtp_settings = {
24
+ :address => 'smtp.sendgrid.net',
25
+ :port => '587',
26
+ :authentication => :plain,
27
+ :user_name => ENV['SENDGRID_USERNAME'],
28
+ :password => ENV['SENDGRID_PASSWORD'],
29
+ :domain => 'heroku.com'
30
+ }
31
+ ActionMailer::Base.delivery_method = :smtp
32
+ }
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -1,6 +1,10 @@
1
1
  module Bently
2
2
 
3
- class Resque < Recipe
3
+ class Resque < RailsRecipe
4
+
5
+ step :add_gem, "gem 'resque'"
6
+ step :shell, 'bundle install'
7
+
4
8
  end
5
9
 
6
10
  end
@@ -1,18 +1,23 @@
1
1
  module Bently
2
2
 
3
- class RspecRails < Recipe
4
- GEMFILE_DEF = %{group :test, :development do
5
- gem "rspec-rails", "~> 2.0"
6
- end
7
- }
8
- RAILS_GENERATOR = "rails g rspec:install"
3
+ class RspecRails < RailsRecipe
4
+
5
+ step :add_gem
6
+ step :shell, 'bundle install'
7
+ step :shell, "rails g rspec:install"
8
+
9
+ protected
9
10
 
10
- def bake
11
- add_gem(GEMFILE_DEF)
12
- bundle_install
13
- command RAILS_GENERATOR
14
- super
11
+ def add_gem
12
+ super gem_def
15
13
  end
14
+
15
+ def gem_def
16
+ %{group :test, :development do
17
+ gem "rspec-rails", "~> 2.0"
18
+ end}
19
+ end
20
+
16
21
  end
17
22
 
18
23
  end
@@ -0,0 +1,18 @@
1
+ module Bently
2
+
3
+ class Rvmrc < Recipe
4
+
5
+ step :touch_rvmrc
6
+
7
+ def touch_rvmrc
8
+ ruby_version = `rvm current`.chomp
9
+ shell(
10
+ lambda{|gemset| "echo \"rvm use --create #{ruby_version}@#{gemset}\" > .rvmrc" },
11
+ :ask => "Enter a gemset name:",
12
+ :description => "Touch .rvmrc:\nrvm use --create #{ruby_version}@<gemset>"
13
+ )
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -1,16 +1,10 @@
1
1
  module Bently
2
2
 
3
- class TwitterBootstrapRails < Recipe
3
+ class TwitterBootstrapRails < RailsRecipe
4
4
 
5
- GEMFILE_DEF = "gem \"twitter-bootstrap-rails\", :group => :assets"
6
- RAILS_GENERATOR = "rails g bootstrap:install"
7
-
8
- def bake
9
- add_gem(GEMFILE_DEF) || return
10
- bundle_install
11
- command RAILS_GENERATOR
12
- super
13
- end
5
+ step :add_gem, 'gem "twitter-bootstrap-rails", :group => :assets'
6
+ step :shell, 'bundle install'
7
+ step :shell, 'rails g bootstrap:install'
14
8
 
15
9
  end
16
10
 
@@ -2,16 +2,8 @@ module Bently
2
2
 
3
3
  class WelcomeIndex < Recipe
4
4
 
5
- RAILS_GENERATE = 'bundle exec rails g controller welcome index'
6
- ROUTES_FILE = 'config/routes.rb'
7
- GSUB_SEARCH = /#\s*(root :to => 'welcome#index')/
8
- GSUB_REPLACE = '\1'
9
-
10
- def bake
11
- command RAILS_GENERATE
12
- gsub_file ROUTES_FILE, GSUB_SEARCH, GSUB_REPLACE
13
- super
14
- end
5
+ step :shell, 'bundle exec rails g controller welcome index'
6
+ step :modify, :file => 'config/routes.rb', :from => /#\s*(root :to => 'welcome#index')/, :to => '\1'
15
7
 
16
8
  end
17
9
 
data/lib/bently/recipe.rb CHANGED
@@ -1,133 +1,63 @@
1
1
  module Bently
2
-
3
- class Recipe
4
-
5
- BUNDLE_INSTALL = "bundle install"
6
- RECIPE_DIR = "#{BENTLY_REPOSITORY}/lib/bently/recipe/*.rb"
7
-
8
- # list all recipes
9
- def self.list
10
- Dir[RECIPE_DIR].map{ |f| File.basename f, '.rb' }.sort
2
+
3
+ module RecipeMethods
4
+ def self.extended(base)
5
+ base.send(:include, InstanceMethods) if base.is_a? Class
11
6
  end
12
7
 
13
- # get recipe class from name
14
- def self.from_name name
15
- "Bently::#{name.camelize}".constantize
16
- end
17
-
18
-
19
-
20
- def initialize options={}
21
- @read_only = options[:read_only]
8
+ def step(*args)
9
+ step_args << args
22
10
  end
23
11
 
24
- # bake a recipe
25
- def bake
26
- puts_step "Done!"
12
+ def step_args
13
+ @steps_args ||= []
27
14
  end
28
15
 
29
- protected
30
-
31
- # instance to CLI
32
- # for access to Thor helper methods
33
- def cli; @cli ||= CLI.new end
34
-
35
- # add a gem to the Gemfile
36
- def add_gem gem_def
37
- unless @read_only
38
- if confirm_step "Add to Gemfile"
39
- begin
40
- cli.append_to_file 'Gemfile', gem_def
41
- rescue
42
- puts "Gemfile was not found. Aborting.."
43
- return false
44
- end
45
- end
46
- else
47
- puts_quote_step "Add to Gemfile", gem_def
48
- end
49
- true
50
- end
16
+ private
51
17
 
52
- # run bundle install
53
- def bundle_install
54
- command BUNDLE_INSTALL
18
+ def inherited(subclass)
19
+ super
20
+ subclass.step_args.concat self.step_args
55
21
  end
56
22
 
57
- # execute a command
58
- def command cmd
59
- unless @read_only
60
- puts `#{cmd}` if confirm_step cmd
61
- else
62
- puts_step cmd
23
+ module InstanceMethods
24
+ def steps
25
+ @steps ||= parse_steps
63
26
  end
64
- end
65
27
 
66
- # executes a command with user input
67
- def ask_command cmd, prompt
68
- unless @read_only
69
- if confirm_step cmd
70
- resp = cli.ask prompt
71
- puts `#{yield resp}`
28
+ protected
29
+
30
+ def parse_steps
31
+ self.class.step_args.map do |args|
32
+ self.send(args.shift, *args)
72
33
  end
73
- else
74
- puts_step cmd
75
34
  end
76
35
  end
36
+ end
77
37
 
78
- # creates a file
79
- def create_file destination, data
80
- unless @read_only
81
- cli.create_file destination, data if confirm_step "Touch #{destination}"
82
- else
83
- puts_quote_step "Touch #{destination}", data
84
- end
85
- end
38
+ class Recipe
39
+ extend RecipeMethods
86
40
 
87
- # gsubs a file
88
- def gsub_file file, search, replace
89
- unless @read_only
90
- if confirm_step "Edit #{file}"
91
- cli.gsub_file file, search, replace
92
- end
93
- else
94
- puts_step "Edit #{file}"
95
- end
96
- end
41
+ # step :shell, command
42
+ def shell(*args); StepShell.new(*args) end
97
43
 
98
- # outputs a step with a blockquote
99
- def puts_quote_step text, quote
100
- puts_step "#{text}"
101
- puts
102
- puts "#{quote}"
103
- puts
104
- end
44
+ # step :touch, :file => filename, :with => data
45
+ def touch(*args) StepTouch.new(*args) end
105
46
 
106
- # outputs a step for confirmation
107
- def confirm_step text
108
- cli.yes? "#{magenta('==>')} #{bold(text)}?"
109
- end
47
+ # step :modify, :file => filename, :from => pattern, :to => replacement
48
+ def modify(*args) StepModify.new(*args) end
110
49
 
111
- # outputs a step
112
- def puts_step text
113
- puts "#{magenta('==>')} #{bold(text)}"
114
- end
50
+ # step :append, :file => filename, :with => data
51
+ def append(*args) StepAppend.new(*args) end
115
52
 
116
- # colorizes text
117
- def colorize(text, color_code)
118
- "#{color_code}#{text}\033[0m"
119
- end
53
+ # step :prepend, :file => filename, :with => data
54
+ def prepend(*args) StepPrepend.new(*args) end
120
55
 
121
- def red(text); colorize(text, "\033[31m"); end
122
- def green(text); colorize(text, "\033[32m"); end
123
- def magenta(text); colorize(text, "\033[35m"); end
124
- def light_green(text); colorize(text, "\033[32m"); end
125
- def bold(text); "\033[1m#{text}\033[22m"; end
56
+ # step :insert, :file => filename, :with => data, :after => some_text
57
+ def insert(*args) StepInsert.new(*args) end
126
58
 
59
+ # step :remove, :file => filename
60
+ def remove(*args) StepRemove.new(*args) end
127
61
  end
128
- end
129
62
 
130
- # load recipes
131
- Dir["#{Bently::BENTLY_REPOSITORY}/lib/bently/recipe/*.rb"].map{ |f| File.basename f, '.rb' }.each do |f|
132
- require 'bently/recipe/' + f
133
63
  end
@@ -0,0 +1,15 @@
1
+ module Bently
2
+
3
+ class RecipeBook
4
+
5
+ RECIPE_DIR = "#{BENTLY_REPOSITORY}/lib/bently/recipe/*.rb"
6
+
7
+ def self.all
8
+ Dir[RECIPE_DIR].map{ |f| File.basename f, '.rb' }.sort
9
+ end
10
+
11
+ def self.find(recipe)
12
+ "Bently::#{recipe.camelize}".constantize
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ module Bently
2
+
3
+ class RailsRecipe < Recipe
4
+ GEMFILE = 'Gemfile'
5
+
6
+ # step :add_gem, "gem 'rails'"
7
+ def add_gem *args
8
+ data = args.shift
9
+ append :file => GEMFILE, :with => data
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,93 @@
1
+ module Bently
2
+
3
+ class Step
4
+ def initialize(*args)
5
+ end
6
+ def question; nil end
7
+ def fail_on_skip?; false end
8
+ end
9
+
10
+ class StepShell < Step
11
+ attr_reader :command
12
+ def initialize(*args)
13
+ @command = args.shift
14
+ @options = args.first || {}
15
+ end
16
+ def action; @options[:action] || 'execute' end
17
+ def question; @options[:ask] end
18
+ def description
19
+ return @options[:description] if @options[:description]
20
+ command_desc = command
21
+ if command_desc.is_a?(Proc)
22
+ placeholder = '...'
23
+ command_desc = command_desc.yield(placeholder)
24
+ end
25
+ "Execute:\n#{command_desc}"
26
+ end
27
+ def fail_on_skip?; @options[:fail_on_skip] end
28
+ end
29
+
30
+ class StepTouch < Step
31
+ attr_reader :file, :data
32
+ def initialize(*args)
33
+ opts = args.first
34
+ @file, @data = [:file,:with].map{|k| opts[k]}
35
+ end
36
+ def action; 'touch' end
37
+ def description; "Touch #{file}:\n#{data}" end
38
+ end
39
+
40
+ class StepModify < Step
41
+ attr_reader :file, :pattern, :replacement
42
+ def initialize(*args)
43
+ opts = args.first
44
+ @file, @pattern, @replacement = [:file,:from,:to].map{|k| opts[k]}
45
+ end
46
+ def action; 'modify' end
47
+ def description
48
+ "Modify #{file}:\n#{pattern.inspect} =>\n#{replacement}"
49
+ end
50
+ end
51
+
52
+ class StepAppend < Step
53
+ attr_reader :file, :data
54
+ def initialize(*args)
55
+ opts = args.first
56
+ @file, @data = [:file,:with].map{|k| opts[k]}
57
+ end
58
+ def action; 'append' end
59
+ def description; "Append to #{file}:\n#{data}" end
60
+ end
61
+
62
+ class StepPrepend < Step
63
+ attr_reader :file, :data
64
+ def initialize(*args)
65
+ opts = args.first
66
+ @file, @data = [:file,:with].map{|k| opts[k]}
67
+ end
68
+ def action; 'prepend' end
69
+ def description; "Prepend to #{file}:\n#{data}" end
70
+ end
71
+
72
+ class StepInsert < Step
73
+ attr_reader :file, :data, :options
74
+ def initialize(*args)
75
+ opts = args.first
76
+ @file, @data = [:file,:with].map{|k| opts.delete(k) }
77
+ @options = opts
78
+ end
79
+ def action; 'insert' end
80
+ def description; "Insert into #{file}:\n#{data}" end
81
+ end
82
+
83
+ class StepRemove < Step
84
+ attr_reader :file
85
+ def initialize(*args)
86
+ opts = args.first
87
+ @file = opts.delete(:file)
88
+ end
89
+ def action; 'remove' end
90
+ def description; "Remove #{file}" end
91
+ end
92
+
93
+ end
@@ -0,0 +1,5 @@
1
+ module Bently
2
+
3
+ VERSION = "0.1.0"
4
+
5
+ end
data/lib/bently.rb CHANGED
@@ -2,6 +2,16 @@ require 'thor'
2
2
 
3
3
  require 'bently/core_ext/string'
4
4
  require 'bently/globals'
5
- require 'bently/cli'
5
+ require 'bently/step'
6
6
  require 'bently/recipe'
7
+ require 'bently/recipe_template/rails.rb'
8
+ require 'bently/recipe_book'
9
+ require 'bently/clo'
10
+ require 'bently/himself'
11
+
12
+ Dir[Bently::RecipeBook::RECIPE_DIR].map do |f|
13
+ File.basename f, '.rb'
14
+ end.each do |f|
15
+ require 'bently/recipe/' + f
16
+ end
7
17