redmint_composer 2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/README.textile +10 -0
  3. data/bin/redmint_composer +7 -0
  4. data/lib/rails_wizard.rb +7 -0
  5. data/lib/rails_wizard/command.rb +204 -0
  6. data/lib/rails_wizard/config.rb +88 -0
  7. data/lib/rails_wizard/diagnostics.rb +58 -0
  8. data/lib/rails_wizard/recipe.rb +114 -0
  9. data/lib/rails_wizard/recipes.rb +56 -0
  10. data/lib/rails_wizard/template.rb +111 -0
  11. data/recipes/admin.rb +42 -0
  12. data/recipes/analytics.rb +41 -0
  13. data/recipes/core.rb +32 -0
  14. data/recipes/deployment.rb +178 -0
  15. data/recipes/devise.rb +34 -0
  16. data/recipes/email.rb +65 -0
  17. data/recipes/email_dev.rb +92 -0
  18. data/recipes/example.rb +63 -0
  19. data/recipes/extras.rb +283 -0
  20. data/recipes/frontend.rb +33 -0
  21. data/recipes/gems.rb +274 -0
  22. data/recipes/git.rb +27 -0
  23. data/recipes/init.rb +179 -0
  24. data/recipes/learn_rails.rb +89 -0
  25. data/recipes/locale.rb +31 -0
  26. data/recipes/omniauth.rb +38 -0
  27. data/recipes/pages.rb +91 -0
  28. data/recipes/rails_bootstrap.rb +29 -0
  29. data/recipes/rails_devise.rb +26 -0
  30. data/recipes/rails_devise_pundit.rb +25 -0
  31. data/recipes/rails_devise_roles.rb +25 -0
  32. data/recipes/rails_foundation.rb +29 -0
  33. data/recipes/rails_mailinglist_activejob.rb +76 -0
  34. data/recipes/rails_omniauth.rb +27 -0
  35. data/recipes/rails_signup_download.rb +69 -0
  36. data/recipes/rails_stripe_checkout.rb +84 -0
  37. data/recipes/rails_stripe_coupons.rb +125 -0
  38. data/recipes/rails_stripe_membership_saas.rb +112 -0
  39. data/recipes/railsapps.rb +77 -0
  40. data/recipes/readme.rb +161 -0
  41. data/recipes/roles.rb +40 -0
  42. data/recipes/setup.rb +162 -0
  43. data/recipes/tests.rb +59 -0
  44. data/spec/rails_wizard/config_spec.rb +108 -0
  45. data/spec/rails_wizard/recipe_spec.rb +115 -0
  46. data/spec/rails_wizard/recipes/sanity_spec.rb +30 -0
  47. data/spec/rails_wizard/recipes_spec.rb +41 -0
  48. data/spec/rails_wizard/template_spec.rb +92 -0
  49. data/spec/spec_helper.rb +11 -0
  50. data/spec/support/rails_directory.rb +17 -0
  51. data/spec/support/template_runner.rb +28 -0
  52. data/spec/test_recipes/test_recipe_in_file.rb +9 -0
  53. data/templates/helpers.erb +138 -0
  54. data/templates/layout.erb +231 -0
  55. data/templates/recipe.erb +13 -0
  56. data/version.rb +3 -0
  57. metadata +201 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 137977fbed3b36d9ef12a590e5f706439824aa18
4
+ data.tar.gz: cd727d83d3c145b8e28d2e3fe9c720946c2c20cc
5
+ SHA512:
6
+ metadata.gz: ea24428e963a6b898e076da461661d7e338c7a9bd7e5b1641fa208ee91f3cb2304b6613517972825d7e63d4425036c8c674de95a362af0970b8a8f88830ef841
7
+ data.tar.gz: 5cf00a1bf3d285ca6632070312a7d08832fbbcd9706d86d167bc5112a0034d41ff4a7add1e21379afc8e179beadd6d515876ffe842fb5d2cd93c6dbbd942fe95
@@ -0,0 +1,10 @@
1
+ h1. Redmint Composer
2
+
3
+ The Redmint Composer gem installs a command line tool to assemble a Rails application from a collection of "recipes." (Based on rails_app_composer gem)
4
+
5
+ <pre>
6
+ $ rvm use 2.2.2
7
+ $ gem install rails
8
+ $ gem install redmint_composer
9
+ $ redmint_composer new myapp -r core
10
+ </pre>
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ $:.push File.dirname(__FILE__) + '/../lib'
3
+
4
+ require 'rubygems'
5
+ require 'rails_wizard/command'
6
+
7
+ RailsWizard::Command.start
@@ -0,0 +1,7 @@
1
+ require 'rails_wizard/recipes'
2
+ require 'rails_wizard/recipe'
3
+ require 'rails_wizard/config'
4
+ require 'rails_wizard/diagnostics'
5
+ require 'rails_wizard/template'
6
+
7
+ RailsWizard::Recipes.add_from_directory(File.dirname(__FILE__) + '/../recipes')
@@ -0,0 +1,204 @@
1
+ require 'rails_wizard'
2
+ require 'thor'
3
+
4
+ module RailsWizard
5
+ class Command < Thor
6
+ include Thor::Actions
7
+ desc "new APP_NAME", "create a new Rails app"
8
+ method_option :recipes, :type => :array, :aliases => "-r"
9
+ method_option :defaults, :type => :string, :aliases => "-d"
10
+ method_option :recipe_dirs, :type => :array, :aliases => "-l"
11
+ method_option :no_default_recipes, :type => :boolean, :aliases => "-L"
12
+ method_option :template_root, :type => :string, :aliases => '-t'
13
+ method_option :quiet, :type => :boolean, :aliases => "-q", :default => false
14
+ method_option :verbose, :type => :boolean, :aliases => "-V", :default => false
15
+ def new(name)
16
+ add_recipes
17
+ recipes, defaults = load_defaults
18
+ (print "\ndefaults: "; p defaults) if options[:verbose]
19
+ args = ask_for_args(defaults)
20
+ (print "\nargs: "; p args) if options[:verbose]
21
+ recipes = ask_for_recipes(recipes)
22
+ (print "\nrecipes: "; p recipes) if options[:verbose]
23
+ gems = ask_for_gems(defaults)
24
+ (print "\ngems: "; p gems) if options[:verbose]
25
+ run_template(name, recipes, gems, args, defaults, nil)
26
+ end
27
+
28
+ desc "template TEMPLATE_FILE", "create a new Rails template"
29
+ method_option :recipes, :type => :array, :aliases => "-r"
30
+ method_option :defaults, :type => :string, :aliases => "-d"
31
+ method_option :recipe_dirs, :type => :array, :aliases => "-l"
32
+ method_option :no_default_recipes, :type => :boolean, :aliases => "-L"
33
+ method_option :template_root, :type => :string, :aliases => '-t'
34
+ method_option :quiet, :type => :boolean, :aliases => "-q", :default => false
35
+ method_option :verbose, :type => :boolean, :aliases => "-V", :default => false
36
+ def template(template_name)
37
+ add_recipes
38
+ recipes, defaults = load_defaults
39
+ recipes = ask_for_recipes(recipes)
40
+ gems = ask_for_gems(defaults)
41
+ run_template(nil, recipes, gems, nil, defaults, template_name)
42
+ end
43
+
44
+ desc "list [CATEGORY]", "list available recipes (optionally by category)"
45
+ def list(category = nil)
46
+ recipes = if category
47
+ RailsWizard::Recipes.for(category).map{|e| RailsWizard::Recipe.from_mongo e}
48
+ else
49
+ RailsWizard::Recipes.list_classes
50
+ end
51
+ address = 'https://github.com/RailsApps/rails_apps_composer/wiki/tutorial-rails-apps-composer#recipes'
52
+ say("To learn more about recipes, see:\n#{address}", [:bold, :cyan])
53
+ # https://github.com/wycats/thor/blob/master/lib/thor/shell/basic.rb
54
+ recipes.each{|e| say("#{e.key.ljust 15}# #{e.description}")}
55
+ end
56
+
57
+ no_tasks do
58
+
59
+ def add_recipes
60
+ Recipes.clear if options[:no_default_recipes]
61
+ if dirs = options[:recipe_dirs]
62
+ dirs.each {|d| Recipes.add_from_directory d}
63
+ end
64
+ end
65
+
66
+ def load_defaults
67
+ # Load defaults from a file; if a file specifies recipes, they'll be run *before*
68
+ # any on the command line (or prompted for)..
69
+ return [[], {}] unless options[:defaults]
70
+ defaults = Kernel.open(options[:defaults]) {|f| YAML.load(f) }
71
+ recipes = defaults.delete('recipes') { [] }
72
+ [recipes, defaults]
73
+ end
74
+
75
+ def print_recipes(recipes)
76
+ say("\nAvailable Recipes:", [:bold, :cyan])
77
+ RailsWizard::Recipes.categories.each do |category|
78
+ say("#{category} ", [:bold, :cyan])
79
+ a = RailsWizard::Recipes.for(category)
80
+ a.each_with_index do |e,i|
81
+ s = (a.length - 1 == i) ? "#{e}" : "#{e}, "
82
+ if recipes.include?(e)
83
+ say(s, [:bold, :green])
84
+ else
85
+ say(s)
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ def ask_for_recipes(recipes)
92
+ return recipes + options[:recipes] if options[:recipes]
93
+ return recipes if options[:quiet]
94
+ loop do
95
+ recipe = prompt_for_recipes(recipes)
96
+ break if '' == recipe
97
+ case
98
+ when recipes.include?(recipe)
99
+ recipes -= [recipe]
100
+ when RailsWizard::Recipes.list.include?(recipe)
101
+ recipes << recipe
102
+ else
103
+ say("\n> Invalid recipe, please try again.", :red)
104
+ end
105
+ end
106
+ recipes
107
+ end
108
+
109
+ def prompt_for_recipes(recipes)
110
+ print_recipes(recipes)
111
+ say("\nWhich recipe would you like to add? ", :bold)
112
+ ask('(blank to finish)', :yellow)
113
+ end
114
+
115
+ def ask_for_gems(defaults)
116
+ gems = defaults["gems"] || []
117
+ return gems if options[:quiet]
118
+ loop do
119
+ getgem = prompt_for_gems
120
+ break if '' == getgem
121
+ gems << getgem.downcase
122
+ end
123
+ gems
124
+ end
125
+
126
+ def prompt_for_gems
127
+ say('What gem would you like to add? ', :bold)
128
+ ask('(blank to finish)', :yellow)
129
+ end
130
+
131
+ def ask_for_arg(question, default = nil)
132
+ return default unless default.nil?
133
+ say("#{question} ", :bold)
134
+ result = nil
135
+ loop do
136
+ answer = ask('(y/n)', :yellow)
137
+ case answer.downcase
138
+ when "yes", "y"
139
+ result = true
140
+ break
141
+ when "no", "n"
142
+ result = false
143
+ break
144
+ end
145
+ end
146
+ result
147
+ end
148
+
149
+ def ask_for_args(defaults)
150
+ args = []
151
+ default_args = defaults["args"] || {}
152
+ s = 'Would you like to skip'
153
+
154
+ question = "#{s} Test::Unit? (yes for RSpec)"
155
+ args << "-T" if ask_for_arg(question, default_args[:skip_test_unit])
156
+
157
+ question = "#{s} Active Record? (yes for MongoDB)"
158
+ args << "-O" if ask_for_arg(question, default_args[:skip_active_record])
159
+
160
+ args
161
+ end
162
+
163
+ def make_red(s)
164
+ # http://en.wikipedia.org/wiki/ANSI_escape_code
165
+ # http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Literals#Backslash_Notation
166
+ "\e[31m#{s}\e[0m"
167
+ end
168
+
169
+ #pass in name if you want to create a rails app
170
+ #pass in file_name if you want to create a template
171
+ def run_template(name, recipes, gems, args, defaults, file_name=nil)
172
+ if opt = options[:template_root]
173
+ RailsWizard::Template.template_root = opt
174
+ end
175
+
176
+ file = if file_name
177
+ File.new(file_name,'w')
178
+ else
179
+ Tempfile.new('template')
180
+ end
181
+ begin
182
+ template = RailsWizard::Template.new(recipes, gems, args, defaults)
183
+ file.write template.compile
184
+ file.close
185
+ if name
186
+ args_list = (args | template.args).join(' ')
187
+ say('Generating basic application, using: ')
188
+ say("\"rails new #{name} -m <temp_file> #{args_list}\"")
189
+ system "rails new #{name} -m #{file.path} #{args_list}"
190
+ else
191
+ say('Generating and saving application template... ')
192
+ say('Done. ')
193
+ say('Generate a new application with the command: ')
194
+ say("\"rails new <APP_NAME> -m #{file.path} #{template.args.join ' '}\"")
195
+ end
196
+ rescue RailsWizard::UnknownRecipeError
197
+ raise Thor::Error.new(make_red("> #{$!.message}."))
198
+ ensure
199
+ file.unlink unless file_name
200
+ end
201
+ end
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,88 @@
1
+ require 'active_support/ordered_hash'
2
+
3
+ module RailsWizard
4
+ class Config
5
+ attr_reader :questions, :defaults
6
+
7
+ def initialize(schema, defaults=nil)
8
+ @questions = ActiveSupport::OrderedHash.new
9
+ @defaults = defaults
10
+ schema.each do |hash|
11
+ key = hash.keys.first
12
+ details = hash.values.first
13
+
14
+ kind = details['type']
15
+ raise ArgumentError, "Unrecognized question type, must be one of #{QUESTION_TYPES.keys.join(', ')}" unless QUESTION_TYPES.keys.include?(kind)
16
+ @questions[key] = QUESTION_TYPES[kind].new(details)
17
+ end
18
+ end
19
+
20
+ def compile(values = {})
21
+ result = []
22
+ values.merge!(defaults) if defaults
23
+ result << "config = #{values.inspect}"
24
+ @questions.each_pair do |key, question|
25
+ result << "config['#{key}'] = #{question.compile} unless config.key?('#{key}') || prefs.has_key?(:#{key})"
26
+ end
27
+ result.join("\n")
28
+ end
29
+
30
+ class Prompt
31
+ attr_reader :prompt, :details
32
+ def initialize(details)
33
+ @details = details
34
+ @prompt = details['prompt']
35
+ end
36
+
37
+ def compile
38
+ "#{question} if #{conditions}"
39
+ end
40
+
41
+ def question
42
+ "ask_wizard(#{prompt.inspect})"
43
+ end
44
+
45
+ def conditions
46
+ [config_conditions, recipe_conditions].join(' && ')
47
+ end
48
+
49
+ def config_conditions
50
+ if details['if']
51
+ "config['#{details['if']}']"
52
+ elsif details['unless']
53
+ "!config['#{details['unless']}']"
54
+ else
55
+ 'true'
56
+ end
57
+ end
58
+
59
+ def recipe_conditions
60
+ if details['if_recipe']
61
+ "recipe?('#{details['if_recipe']}')"
62
+ elsif details['unless_recipe']
63
+ "!recipe?('#{details['unless_recipe']}')"
64
+ else
65
+ 'true'
66
+ end
67
+ end
68
+ end
69
+
70
+ class TrueFalse < Prompt
71
+ def question
72
+ "yes_wizard?(#{prompt.inspect})"
73
+ end
74
+ end
75
+
76
+ class MultipleChoice < Prompt
77
+ def question
78
+ "multiple_choice(#{prompt.inspect}, #{@details['choices'].inspect})"
79
+ end
80
+ end
81
+
82
+ QUESTION_TYPES = {
83
+ 'boolean' => TrueFalse,
84
+ 'string' => Prompt,
85
+ 'multiple_choice' => MultipleChoice
86
+ }
87
+ end
88
+ end
@@ -0,0 +1,58 @@
1
+ module RailsWizard
2
+ module Diagnostics
3
+
4
+ ### collections of recipes that are known to work together
5
+ @@recipes = []
6
+ @@recipes << %w(example)
7
+ @@recipes << %w(setup)
8
+ @@recipes << %w(railsapps)
9
+ @@recipes << %w(gems setup)
10
+ @@recipes << %w(gems readme setup)
11
+ @@recipes << %w(extras gems readme setup)
12
+ @@recipes << %w(example git)
13
+ @@recipes << %w(git setup)
14
+ @@recipes << %w(git railsapps)
15
+ @@recipes << %w(gems git setup)
16
+ @@recipes << %w(gems git readme setup)
17
+ @@recipes << %w(extras gems git readme setup)
18
+ @@recipes << %w(email extras frontend gems git init railsapps readme setup testing)
19
+ @@recipes << %w(core email extras frontend gems git init railsapps readme setup testing)
20
+ @@recipes << %w(core email extras frontend gems git init railsapps readme setup testing)
21
+ @@recipes << %w(core email extras frontend gems git init railsapps readme setup testing)
22
+ @@recipes << %w(email example extras frontend gems git init railsapps readme setup testing)
23
+ @@recipes << %w(email example extras frontend gems git init railsapps readme setup testing)
24
+ @@recipes << %w(email example extras frontend gems git init railsapps readme setup testing)
25
+ @@recipes << %w(apps4 core email extras frontend gems git init railsapps readme setup testing)
26
+ @@recipes << %w(apps4 core email extras frontend gems git init railsapps readme setup tests)
27
+ @@recipes << %w(apps4 core deployment email extras frontend gems git init railsapps readme setup testing)
28
+ @@recipes << %w(apps4 core deployment email extras frontend gems git init railsapps readme setup tests)
29
+ @@recipes << %w(apps4 core deployment devise email extras frontend gems git init omniauth pundit railsapps readme setup tests)
30
+
31
+ ### collections of preferences that are known to work together
32
+
33
+ # ignore these preferences (because they don't cause conflicts)
34
+ # :ban_spiders
35
+ # :better_errors
36
+ # :dev_webserver
37
+ # :git
38
+ # :github
39
+ # :jsruntime
40
+ # :local_env_file
41
+ # :main_branch
42
+ # :prelaunch_branch
43
+ # :prod_webserver
44
+ # :quiet_assets
45
+ # :rvmrc
46
+ # :templates
47
+
48
+ @@prefs = []
49
+
50
+ def self.recipes
51
+ @@recipes
52
+ end
53
+
54
+ def self.prefs
55
+ @@prefs
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,114 @@
1
+ require 'rails_wizard/config'
2
+
3
+ require 'active_support/inflector'
4
+ require 'yaml'
5
+ require 'erb'
6
+
7
+ module RailsWizard
8
+ class Recipe
9
+ extend Comparable
10
+
11
+ def self.<=>(another)
12
+ return -1 if another.run_after.include?(self.key) || self.run_before.include?(another.key)
13
+ return 1 if another.run_before.include?(self.key) || self.run_after.include?(another.key)
14
+ self.key <=> another.key
15
+ end
16
+
17
+ ATTRIBUTES = %w(key args category name description template config exclusive tags run_before run_after requires defaults)
18
+ DEFAULT_ATTRIBUTES = {
19
+ :category => 'other',
20
+ :args => [],
21
+ :tags => [],
22
+ :run_after => [],
23
+ :run_before => [],
24
+ :requires => []
25
+ }
26
+
27
+ def self.generate(key, template_or_file, attributes = {})
28
+ if template_or_file.respond_to?(:read)
29
+ file = template_or_file.read
30
+ parts = file.split(/^__END__$/)
31
+ raise ArgumentError, "The recipe file must have YAML matter after an __END__" unless parts.size == 2
32
+ template = parts.first.strip
33
+ attributes = YAML.load(parts.last).inject({}) do |h,(k,v)|
34
+ h[k.to_sym] = v
35
+ h
36
+ end.merge!(attributes)
37
+ else
38
+ template = template_or_file
39
+ end
40
+
41
+ recipe_class = Class.new(RailsWizard::Recipe)
42
+ recipe_class.attributes = attributes
43
+ recipe_class.template = template
44
+ recipe_class.key = key
45
+
46
+ recipe_class
47
+ end
48
+
49
+ ATTRIBUTES.each do |setter|
50
+ class_eval <<-RUBY
51
+ def self.#{setter}
52
+ attributes[:#{setter}]
53
+ end
54
+
55
+ def self.#{setter}=(val)
56
+ attributes[:#{setter}] = val
57
+ end
58
+
59
+ def #{setter}
60
+ self.class.#{setter}
61
+ end
62
+ RUBY
63
+ end
64
+
65
+ # The attributes hash containing any set values for
66
+ def self.attributes
67
+ @attributes ||= DEFAULT_ATTRIBUTES.dup
68
+ end
69
+
70
+ def self.attributes=(hash)
71
+ attributes.merge! hash
72
+ end
73
+
74
+ def self.config
75
+ return nil unless attributes[:config]
76
+ RailsWizard::Config.new(attributes[:config], attributes[:defaults])
77
+ end
78
+
79
+ def attributes
80
+ self.class.attributes
81
+ end
82
+
83
+ def self.compile
84
+ "# >#{"[ #{name} ]".center(75,'-')}<\n\n# #{description}\nsay_recipe '#{name}'\n\n#{template}\n"
85
+ end
86
+ def compile; self.class.compile end
87
+
88
+ def self.to_mongo(value)
89
+ case value
90
+ when Class
91
+ value.key
92
+ when String
93
+ value
94
+ end
95
+ end
96
+
97
+ def self.from_mongo(key)
98
+ return key if (key.respond_to?(:superclass) && key.superclass == RailsWizard::Recipe)
99
+ return RailsWizard::Recipes[key] if RailsWizard::Recipes[key]
100
+ raise(RailsWizard::UnknownRecipeError.new(key))
101
+ end
102
+
103
+ def self.get_binding
104
+ binding
105
+ end
106
+ end
107
+
108
+ class UnknownRecipeError < StandardError
109
+ def initialize(key)
110
+ message = "No recipe found with name '#{key}'"
111
+ super(message)
112
+ end
113
+ end
114
+ end