redmint_composer 2.3

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.
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