appscrolls 0.7.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.
Files changed (110) hide show
  1. data/.gitignore +8 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +6 -0
  4. data/ChangeLog.md +63 -0
  5. data/Gemfile +3 -0
  6. data/Guardfile +18 -0
  7. data/MIT_LICENSE +20 -0
  8. data/README.md +154 -0
  9. data/Rakefile +78 -0
  10. data/appscrolls.gemspec +32 -0
  11. data/bin/appscrolls +7 -0
  12. data/features/step_definitions/common_steps.rb +211 -0
  13. data/features/support/common.rb +51 -0
  14. data/features/support/env.rb +18 -0
  15. data/lib/appscrolls.rb +10 -0
  16. data/lib/appscrolls/command.rb +85 -0
  17. data/lib/appscrolls/config.rb +86 -0
  18. data/lib/appscrolls/scroll.rb +106 -0
  19. data/lib/appscrolls/scrolls.rb +38 -0
  20. data/lib/appscrolls/template.rb +67 -0
  21. data/lib/rails/generators/.DS_Store +0 -0
  22. data/lib/rails/generators/run_template/USAGE +13 -0
  23. data/lib/rails/generators/run_template/run_template_generator.rb +13 -0
  24. data/sample.rb +75 -0
  25. data/scrolls/active_admin.rb +19 -0
  26. data/scrolls/capybara.rb +34 -0
  27. data/scrolls/cucumber.rb +21 -0
  28. data/scrolls/delayed_job.rb +94 -0
  29. data/scrolls/env_yaml.rb +53 -0
  30. data/scrolls/eycloud.rb +72 -0
  31. data/scrolls/eycloud_recipes_on_deploy.rb +20 -0
  32. data/scrolls/git.rb +17 -0
  33. data/scrolls/github.rb +38 -0
  34. data/scrolls/guard.rb +75 -0
  35. data/scrolls/jquery.rb +11 -0
  36. data/scrolls/mysql.rb +51 -0
  37. data/scrolls/passenger.rb +11 -0
  38. data/scrolls/postgresql.rb +54 -0
  39. data/scrolls/prototype.rb +21 -0
  40. data/scrolls/puma.rb +11 -0
  41. data/scrolls/rails_basics.rb +54 -0
  42. data/scrolls/redis.rb +19 -0
  43. data/scrolls/resque.rb +59 -0
  44. data/scrolls/rspec.rb +21 -0
  45. data/scrolls/simple_form.rb +19 -0
  46. data/scrolls/split.rb +35 -0
  47. data/scrolls/spork.rb +19 -0
  48. data/scrolls/sqlite3.rb +10 -0
  49. data/scrolls/test_unit.rb +11 -0
  50. data/scrolls/thin.rb +10 -0
  51. data/scrolls/twitter_bootstrap.rb +41 -0
  52. data/scrolls/unicorn.rb +10 -0
  53. data/scrolls/zzz/activerecord.rb +69 -0
  54. data/scrolls/zzz/cancan.rb +16 -0
  55. data/scrolls/zzz/carrierwave.rb +42 -0
  56. data/scrolls/zzz/carrierwave_direct.rb +13 -0
  57. data/scrolls/zzz/cartographer.rb +33 -0
  58. data/scrolls/zzz/devise.rb +52 -0
  59. data/scrolls/zzz/devise_invitable.rb +23 -0
  60. data/scrolls/zzz/event_calendar.rb +12 -0
  61. data/scrolls/zzz/factory_girl.rb +38 -0
  62. data/scrolls/zzz/ffaker.rb +22 -0
  63. data/scrolls/zzz/fixture_builder.rb +35 -0
  64. data/scrolls/zzz/forgery.rb +15 -0
  65. data/scrolls/zzz/haml.rb +11 -0
  66. data/scrolls/zzz/heroku.rb +58 -0
  67. data/scrolls/zzz/hoptoad.rb +34 -0
  68. data/scrolls/zzz/inherited_resources.rb +12 -0
  69. data/scrolls/zzz/intercom.rb +35 -0
  70. data/scrolls/zzz/jammit.rb +43 -0
  71. data/scrolls/zzz/jasmine.rb +12 -0
  72. data/scrolls/zzz/mini_magick.rb +13 -0
  73. data/scrolls/zzz/mongo_mapper.rb +20 -0
  74. data/scrolls/zzz/mongohq.rb +61 -0
  75. data/scrolls/zzz/mongoid.rb +20 -0
  76. data/scrolls/zzz/mootools.rb +23 -0
  77. data/scrolls/zzz/newrelic.rb +11 -0
  78. data/scrolls/zzz/nifty_generators.rb +21 -0
  79. data/scrolls/zzz/oa_oauth.rb +12 -0
  80. data/scrolls/zzz/omniauth.rb +55 -0
  81. data/scrolls/zzz/paper_trail.rb +17 -0
  82. data/scrolls/zzz/pow.rb +12 -0
  83. data/scrolls/zzz/rails_admin.rb +22 -0
  84. data/scrolls/zzz/rails_dev_tweaks.rb +10 -0
  85. data/scrolls/zzz/rails_erd.rb +9 -0
  86. data/scrolls/zzz/rails_footnotes.rb +14 -0
  87. data/scrolls/zzz/ransack.rb +32 -0
  88. data/scrolls/zzz/rmagick.rb +13 -0
  89. data/scrolls/zzz/sass.rb +13 -0
  90. data/scrolls/zzz/sequel.rb +13 -0
  91. data/scrolls/zzz/settingslogic.rb +43 -0
  92. data/scrolls/zzz/shoulda_matchers.rb +11 -0
  93. data/scrolls/zzz/sidekiq.rb +23 -0
  94. data/scrolls/zzz/slim.rb +11 -0
  95. data/scrolls/zzz/thinking_sphinx.rb +14 -0
  96. data/scrolls/zzz/vanity.rb +35 -0
  97. data/spec/appscrolls/config_spec.rb +99 -0
  98. data/spec/appscrolls/scroll_spec.rb +103 -0
  99. data/spec/appscrolls/scrolls/sanity_spec.rb +30 -0
  100. data/spec/appscrolls/scrolls_spec.rb +24 -0
  101. data/spec/appscrolls/template_spec.rb +57 -0
  102. data/spec/spec_helper.rb +11 -0
  103. data/spec/support/rails_directory.rb +17 -0
  104. data/spec/support/template_runner.rb +28 -0
  105. data/templates/helpers.erb +45 -0
  106. data/templates/layout.erb +44 -0
  107. data/templates/new_scroll.erb +28 -0
  108. data/templates/scroll.erb +10 -0
  109. data/version.rb +3 -0
  110. metadata +297 -0
@@ -0,0 +1,51 @@
1
+ module CommonHelpers
2
+ def get_command_output
3
+ strip_color_codes(File.read(@stdout)).chomp
4
+ end
5
+
6
+ def strip_color_codes(text)
7
+ text.gsub(/\e\[\d+m/, '')
8
+ end
9
+
10
+ def in_tmp_folder(&block)
11
+ FileUtils.chdir(@tmp_root, &block)
12
+ end
13
+
14
+ def in_project_folder(&block)
15
+ project_folder = @active_project_folder || @tmp_root
16
+ FileUtils.chdir(project_folder, &block)
17
+ end
18
+
19
+ def in_home_folder(&block)
20
+ FileUtils.chdir(@home_path, &block)
21
+ end
22
+
23
+ def force_local_lib_override(project_name = @project_name)
24
+ rakefile = File.read(File.join(project_name, 'Rakefile'))
25
+ File.open(File.join(project_name, 'Rakefile'), "w+") do |f|
26
+ f << "$:.unshift('#{@lib_path}')\n"
27
+ f << rakefile
28
+ end
29
+ end
30
+
31
+ def setup_active_project_folder project_name
32
+ @active_project_folder = File.join(@tmp_root, project_name)
33
+ @project_name = project_name
34
+ end
35
+
36
+ # capture both [stdout, stderr] as well as stdin
37
+ def capture_stdios(input = nil, &block)
38
+ require 'stringio'
39
+ org_stdin, $stdin = $stdin, StringIO.new(input) if input
40
+ org_stdout, $stdout = $stdout, StringIO.new
41
+ org_stderr, $stderr = $stdout, StringIO.new
42
+ yield
43
+ return [$stdout.string, $stderr.string]
44
+ ensure
45
+ $stderr = org_stderr
46
+ $stdout = org_stdout
47
+ $stdin = org_stdin
48
+ end
49
+ end
50
+
51
+ World(CommonHelpers)
@@ -0,0 +1,18 @@
1
+ $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../../lib'))
2
+ require 'bundler/setup'
3
+ require 'appscrolls'
4
+
5
+ path = ENV['PATH']
6
+
7
+ Before do
8
+ @tmp_root = File.dirname(__FILE__) + "/../../tmp"
9
+ @active_project_folder = @tmp_root
10
+ @home_path = File.expand_path(File.join(@tmp_root, "home"))
11
+ @lib_path = File.expand_path(File.dirname(__FILE__) + "/../../lib")
12
+ @fixtures_path = File.expand_path(File.dirname(__FILE__) + "/../../fixtures")
13
+ FileUtils.rm_rf @tmp_root
14
+ FileUtils.mkdir_p @home_path
15
+ ENV['HOME'] = @home_path
16
+ fixture_bin_path = File.expand_path('../../../fixtures/bin', __FILE__)
17
+ ENV['PATH'] = fixture_bin_path + ":" + path
18
+ end
@@ -0,0 +1,10 @@
1
+ require 'appscrolls/scrolls'
2
+ require 'appscrolls/scroll'
3
+ require 'appscrolls/config'
4
+ require 'appscrolls/template'
5
+
6
+ Dir[File.dirname(__FILE__) + '/../scrolls/*.rb'].each do |path|
7
+ key = File.basename(path, '.rb')
8
+ scroll = AppScrollsScrolls::Scroll.generate(key, File.open(path))
9
+ AppScrollsScrolls::Scrolls.add(scroll)
10
+ end
@@ -0,0 +1,85 @@
1
+ require 'appscrolls'
2
+ require 'thor'
3
+
4
+ module AppScrollsScrolls
5
+ class Command < Thor
6
+ include Thor::Actions
7
+ desc "new APP_NAME", "create a new Rails app"
8
+ method_option :scrolls, :type => :array, :aliases => "-s", :desc => "List scrolls, e.g. -s resque rails_basics jquery"
9
+ method_option :template, :type => :boolean, :aliases => "-t", :desc => "Only display template that would be used"
10
+ def new(name)
11
+ if options[:scrolls]
12
+ run_template(name, options[:scrolls], options[:template])
13
+ else
14
+ @scrolls = []
15
+
16
+ while scroll = ask("#{print_scrolls}#{bold}Which scroll would you like to add? #{clear}#{yellow}(blank to finish)#{clear}")
17
+ if scroll == ''
18
+ run_template(name, @scrolls)
19
+ break
20
+ elsif AppScrollsScrolls::Scrolls.list.include?(scroll)
21
+ @scrolls << scroll
22
+ puts
23
+ puts "> #{green}Added '#{scroll}' to template.#{clear}"
24
+ else
25
+ puts
26
+ puts "> #{red}Invalid scroll, please try again.#{clear}"
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ desc "list [CATEGORY]", "list available scrolls (optionally by category)"
33
+ def list(category = nil)
34
+ if category
35
+ scrolls = AppScrollsScrolls::Scrolls.for(category).map{|r| AppScrollsScrolls::Scroll.from_mongo(r) }
36
+ else
37
+ scrolls = AppScrollsScrolls::Scrolls.list_classes
38
+ end
39
+
40
+ scrolls.each do |scroll|
41
+ puts scroll.key.ljust(15) + "# #{scroll.description}"
42
+ end
43
+ end
44
+
45
+ no_tasks do
46
+ def cyan; "\033[36m" end
47
+ def clear; "\033[0m" end
48
+ def bold; "\033[1m" end
49
+ def red; "\033[31m" end
50
+ def green; "\033[32m" end
51
+ def yellow; "\033[33m" end
52
+
53
+ def print_scrolls
54
+ puts
55
+ puts
56
+ puts
57
+ if @scrolls && @scrolls.any?
58
+ puts "#{green}#{bold}Your Scrolls:#{clear} " + @scrolls.join(", ")
59
+ puts
60
+ end
61
+ puts "#{bold}#{cyan}Available Scrolls:#{clear} " + AppScrollsScrolls::Scrolls.list.join(', ')
62
+ puts
63
+ end
64
+
65
+ def run_template(name, scrolls, display_only = false)
66
+ puts
67
+ puts
68
+ puts "#{bold}Generating and Running Template..."
69
+ puts
70
+ file = Tempfile.new('template')
71
+ template = AppScrollsScrolls::Template.new(scrolls)
72
+ file.write template.compile
73
+ file.close
74
+ if display_only
75
+ puts "Template stored to #{file.path}"
76
+ puts File.read(file.path)
77
+ else
78
+ system "rails new #{name} -m #{file.path} #{template.args.join(' ')}"
79
+ end
80
+ ensure
81
+ file.unlink
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,86 @@
1
+ require 'active_support/ordered_hash'
2
+
3
+ module AppScrollsScrolls
4
+ class Config
5
+ attr_reader :questions
6
+
7
+ def initialize(schema)
8
+ @questions = ActiveSupport::OrderedHash.new
9
+ schema.each do |hash|
10
+ key = hash.keys.first
11
+ details = hash.values.first
12
+
13
+ kind = details['type']
14
+ raise ArgumentError, "Unrecognized question type, must be one of #{QUESTION_TYPES.keys.join(', ')}" unless QUESTION_TYPES.keys.include?(kind)
15
+ @questions[key] = QUESTION_TYPES[kind].new(details)
16
+ end
17
+ end
18
+
19
+ def compile(values = {})
20
+ result = []
21
+ result << "config = #{values.inspect}"
22
+ @questions.each_pair do |key, question|
23
+ result << "config['#{key}'] = #{question.compile} unless config.key?('#{key}')"
24
+ end
25
+ result.join("\n")
26
+ end
27
+
28
+ class Prompt
29
+ attr_reader :prompt, :details
30
+ def initialize(details)
31
+ @details = details
32
+ @prompt = details['prompt']
33
+ end
34
+
35
+ def compile
36
+ "#{question} if #{conditions}"
37
+ end
38
+
39
+ def question
40
+ "ask_wizard(#{prompt.inspect})"
41
+ end
42
+
43
+ def conditions
44
+ [config_conditions, scroll_conditions].join(' && ')
45
+ end
46
+
47
+ def config_conditions
48
+ if details['if']
49
+ "config['#{details['if']}']"
50
+ elsif details['unless']
51
+ "!config['#{details['unless']}']"
52
+ else
53
+ 'true'
54
+ end
55
+ end
56
+
57
+ def scroll_conditions
58
+ if details['if_scroll']
59
+ "scroll?('#{details['if_scroll']}')"
60
+ elsif details['unless_scroll']
61
+ "!scroll?('#{details['unless_scroll']}')"
62
+ else
63
+ 'true'
64
+ end
65
+ end
66
+ end
67
+
68
+ class TrueFalse < Prompt
69
+ def question
70
+ "yes_wizard?(#{prompt.inspect})"
71
+ end
72
+ end
73
+
74
+ class MultipleChoice < Prompt
75
+ def question
76
+ "multiple_choice(#{prompt.inspect}, #{@details['choices'].inspect})"
77
+ end
78
+ end
79
+
80
+ QUESTION_TYPES = {
81
+ 'boolean' => TrueFalse,
82
+ 'string' => Prompt,
83
+ 'multiple_choice' => MultipleChoice
84
+ }
85
+ end
86
+ end
@@ -0,0 +1,106 @@
1
+ require 'appscrolls/config'
2
+
3
+ require 'active_support/inflector'
4
+ require 'yaml'
5
+ require 'erb'
6
+
7
+ module AppScrollsScrolls
8
+ class Scroll
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 website)
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 scroll 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
+ scroll_class = Class.new(AppScrollsScrolls::Scroll)
42
+ scroll_class.attributes = attributes
43
+ scroll_class.template = template
44
+ scroll_class.key = key
45
+
46
+ scroll_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
+ AppScrollsScrolls::Config.new(attributes[:config])
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_scroll '#{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 == AppScrollsScrolls::Scroll
99
+ AppScrollsScrolls::Scrolls[key]
100
+ end
101
+
102
+ def self.get_binding
103
+ binding
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,38 @@
1
+ module AppScrollsScrolls
2
+ module Scrolls
3
+ @@categories = {}
4
+ @@list = {}
5
+
6
+ def self.add(scroll)
7
+ AppScrollsScrolls::Scrolls.const_set ActiveSupport::Inflector.camelize(scroll.key), scroll
8
+ @@list[scroll.key] = scroll
9
+ (@@categories[scroll.category.to_s] ||= []) << scroll.key
10
+ @@categories[scroll.category.to_s].uniq!
11
+ scroll
12
+ end
13
+
14
+ def self.[](key)
15
+ @@list[key.to_s]
16
+ end
17
+
18
+ def self.list
19
+ @@list.keys.sort
20
+ end
21
+
22
+ def self.list_classes
23
+ @@list.values.sort_by{|c| c.key}
24
+ end
25
+
26
+ def self.categories
27
+ @@categories.keys.sort
28
+ end
29
+
30
+ def self.for(category)
31
+ (@@categories[category.to_s] || []).sort
32
+ end
33
+
34
+ def self.remove_from_category(category, scroll)
35
+ (@@categories[category.to_s] ||= []).delete(scroll.key)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,67 @@
1
+ module AppScrollsScrolls
2
+ class Template
3
+ attr_reader :scrolls, :unknown_scroll_names
4
+
5
+ def initialize(scrolls)
6
+ @unknown_scroll_names = []
7
+ @scrolls = scrolls.inject([]) do |list, name|
8
+ scroll = AppScrollsScrolls::Scroll.from_mongo(name)
9
+ if scroll
10
+ list << scroll
11
+ else
12
+ @unknown_scroll_names << name
13
+ $stderr.puts "Unknown scroll '#{name}'. Skipping."
14
+ end
15
+ list
16
+ end
17
+ end
18
+
19
+ def self.template_root
20
+ File.dirname(__FILE__) + '/../../templates'
21
+ end
22
+
23
+ def self.render(template_name, binding = nil)
24
+ erb = ERB.new(File.open(template_root + '/' + template_name + '.erb').read)
25
+ erb.result(binding)
26
+ end
27
+ def render(template_name, binding = nil); self.class.render(template_name, binding) end
28
+
29
+
30
+ def resolve_scrolls
31
+ @resolve_scrolls ||= scrolls_with_dependencies.sort
32
+ end
33
+
34
+ def scroll_classes
35
+ @scroll_classes ||= scrolls.map { |name| AppScrollsScrolls::Scroll.from_mongo(name) }
36
+ end
37
+
38
+ def scrolls_with_dependencies
39
+ @scrolls_with_dependencies ||= scroll_classes
40
+
41
+ added_more = false
42
+ for scroll in scroll_classes
43
+ scroll.requires.each do |requirement|
44
+ requirement = AppScrollsScrolls::Scroll.from_mongo(requirement)
45
+ count = @scrolls_with_dependencies.size
46
+ (@scrolls_with_dependencies << requirement).uniq!
47
+ unless @scrolls_with_dependencies.size == count
48
+ added_more = true
49
+ end
50
+ end
51
+ end
52
+
53
+ added_more ? scrolls_with_dependencies : @scrolls_with_dependencies
54
+ end
55
+
56
+ def compile
57
+ render 'layout', binding
58
+ end
59
+
60
+ def args
61
+ scrolls.map(&:args).uniq
62
+ end
63
+
64
+ def custom_code?; false end
65
+ def custom_code; nil end
66
+ end
67
+ end