gem_suit 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/.gitignore +10 -0
  2. data/.suit +4 -0
  3. data/CHANGELOG.rdoc +5 -0
  4. data/Gemfile +3 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.textile +419 -0
  7. data/Rakefile +26 -0
  8. data/VERSION +1 -0
  9. data/bin/suit +10 -0
  10. data/gem_suit.gemspec +26 -0
  11. data/lib/gem_suit/application/actions.rb +203 -0
  12. data/lib/gem_suit/application/test.rb +106 -0
  13. data/lib/gem_suit/application/utils/gemfile.rb +42 -0
  14. data/lib/gem_suit/application/utils.rb +135 -0
  15. data/lib/gem_suit/application.rb +42 -0
  16. data/lib/gem_suit/cli/application/io_buffer.rb +54 -0
  17. data/lib/gem_suit/cli/application/test_loader.rb +5 -0
  18. data/lib/gem_suit/cli/application.rb +159 -0
  19. data/lib/gem_suit/cli/base/shell.rb +41 -0
  20. data/lib/gem_suit/cli/base/utils.rb +83 -0
  21. data/lib/gem_suit/cli/base.rb +15 -0
  22. data/lib/gem_suit/cli/builder/boot +14 -0
  23. data/lib/gem_suit/cli/builder/generator.rb +154 -0
  24. data/lib/gem_suit/cli/builder/rails_app.rb +146 -0
  25. data/lib/gem_suit/cli/builder.rb +143 -0
  26. data/lib/gem_suit/cli/config/hash.rb +61 -0
  27. data/lib/gem_suit/cli/config.rb +37 -0
  28. data/lib/gem_suit/cli.rb +145 -0
  29. data/lib/gem_suit/integration_test.rb +14 -0
  30. data/lib/gem_suit/test_help.rb +17 -0
  31. data/lib/gem_suit/version.rb +9 -0
  32. data/lib/gem_suit.rb +6 -0
  33. data/templates/dynamic/CHANGELOG.rdoc +5 -0
  34. data/templates/dynamic/Gemfile +14 -0
  35. data/templates/dynamic/MIT-LICENSE +20 -0
  36. data/templates/dynamic/README.textile +35 -0
  37. data/templates/dynamic/VERSION +1 -0
  38. data/templates/dynamic/config/boot.rb +13 -0
  39. data/templates/dynamic/config/preinitializer.rb +20 -0
  40. data/templates/dynamic/gitignore +9 -0
  41. data/templates/dynamic/suit/shared/app/views/application/index.html.erb +16 -0
  42. data/templates/dynamic/suit/shared/public/stylesheets/app.css +99 -0
  43. data/templates/dynamic/suit/shared/test/test_helper.rb +37 -0
  44. data/templates/dynamic/suit/templates/shared/Gemfile +14 -0
  45. data/templates/dynamic/suit/templates/shared/config/database-mysql.yml +11 -0
  46. data/templates/dynamic/suit/templates/shared/config/database-sqlite.yml +10 -0
  47. data/templates/static/suit/shared/app/models/.gitkeep +0 -0
  48. data/templates/static/suit/shared/app/views/layouts/application.html.erb +11 -0
  49. data/templates/static/suit/shared/db/schema.rb +2 -0
  50. data/templates/static/suit/shared/db/seeds.rb +7 -0
  51. data/templates/static/suit/shared/test/fixtures/.gitkeep +0 -0
  52. data/templates/static/suit/shared/test/integration/suit/example.rb +40 -0
  53. data/templates/static/suit/shared/test/suit_application/capybara_extensions.rb +36 -0
  54. data/templates/static/suit/shared/test/suit_application.rb +27 -0
  55. data/templates/static/suit/shared/test/unit/.gitkeep +0 -0
  56. data/templates/static/suit/templates/shared/config/initializers/.gitkeep +0 -0
  57. data/templates/static/suit/templates/shared/db/schema.rb +2 -0
  58. metadata +188 -0
@@ -0,0 +1,159 @@
1
+ require "gem_suit/cli/application/io_buffer"
2
+
3
+ module GemSuit
4
+ class CLI < Thor
5
+ module Application
6
+
7
+ def self.included(base)
8
+ base.send :include, InstanceMethods
9
+ end
10
+
11
+ module InstanceMethods
12
+
13
+ def test_suit(file_or_pattern = nil)
14
+ assert_suit_dir
15
+
16
+ data = IOBuffer.capture do |buffer|
17
+ (options.rails_versions || major_rails_versions).each do |rails_version|
18
+ path = "suit/rails-#{rails_version}/dummy/test/integration/suit/"
19
+ match = Dir[File.join(path, "**", "#{file_or_pattern || "*"}.rb")]
20
+ match = Dir[File.join(path, file_or_pattern)] if match.empty?
21
+
22
+ match.each do |f|
23
+ buffer.execute "ruby #{f} #{"-v" if options.very_verbose?}"
24
+ end
25
+ end
26
+ end
27
+
28
+ print_test_results "Suit", data
29
+ end
30
+
31
+ def test_unit(file_or_pattern = nil)
32
+ assert_suit_dir
33
+
34
+ loader = File.expand_path "../application/test_loader.rb", __FILE__
35
+
36
+ proc = Proc.new do |buffer, path|
37
+ buffer.execute "suit restore"
38
+
39
+ match = Dir[File.join(path, "**", "#{file_or_pattern || "*"}.rb")]
40
+ match = Dir[File.join(path, file_or_pattern)] if match.empty?
41
+ files = match.collect{|x| x.inspect}.join " "
42
+
43
+ section = path.match(/suit\/([^\/]*)\//).captures[0].capitalize.gsub "-", " "
44
+ files_desc = match.size == 1 ?
45
+ match.first.gsub(path, "") :
46
+ "#{file_or_pattern.nil? ? "All" : "Multiple"} tests"
47
+
48
+ buffer.log "#{section} - #{files_desc}"
49
+ buffer.execute "ruby #{loader} #{"-I" if match.size > 1}#{files}"
50
+ buffer.execute "suit restore"
51
+ end
52
+
53
+ data = IOBuffer.capture do |buffer|
54
+ if options.rails_versions == ["0"]
55
+ proc.call buffer, "suit/shared/test/unit/"
56
+ else
57
+ (options.rails_versions || major_rails_versions).each do |rails_version|
58
+ proc.call buffer, "suit/rails-#{rails_version}/dummy/test/unit/"
59
+ end
60
+ end
61
+ end
62
+
63
+ print_test_results "Unit", data
64
+ end
65
+
66
+ private
67
+
68
+ def files(action)
69
+ assert_suit_dir
70
+
71
+ log "(in #{File.expand_path("")})"
72
+
73
+ require "suit/shared/test/suit_application.rb"
74
+ application = SuitApplication.new :validate_root_path => false, :verbose => options.verbose?
75
+ Dir["suit/rails-*/dummy"].each do |rails_root|
76
+ application.root_path = rails_root
77
+ application.send :"#{action}_all"
78
+ end
79
+
80
+ log "Done #{action.to_s[0..-2]}ing files".green
81
+ end
82
+
83
+ def rails(command, environment, args = nil)
84
+ assert_suit_dir
85
+
86
+ rails_version = (options.rails_version || major_rails_versions.last).to_i
87
+ root_path = File.expand_path "suit/rails-#{rails_version}/dummy"
88
+ command = {2 => "script/#{command}", 3 => "rails #{command.to_s[0, 1]}"}[rails_version]
89
+
90
+ require "suit/rails-#{rails_version}/dummy/test/suit_application.rb"
91
+ SuitApplication.new(:verbose => options.verbose?).bundle_install
92
+
93
+ system "cd #{root_path} && RAILS_ENV=#{environment} #{command} #{"-p #{options.port}" if options.port}"
94
+ end
95
+
96
+ MAJOR_RAILS_VERSIONS = [2, 3]
97
+ DESCRIPTION_MATCH = /^Setting up test environment for (.*)$/
98
+ LOAD_MATCH = /^Loaded suite suit\/rails-(\d+)\/dummy\/test\/integration\/suit\/(.*)$/
99
+ GEM_SUIT_MATCH = /^GemSuit: (.*)$/
100
+ TIME_MATCH = /^Finished in (.*)\.$/
101
+ SUMMARY_MATCH = /^(\d+) (\w+), (\d+) (\w+), (\d+) (\w+), (\d+) (\w+)$/
102
+
103
+ def print_test_results(section, data)
104
+ return if (suit_tests = extract_test_results(data)).empty?
105
+
106
+ failures = suit_tests.inject(0) do |count, test|
107
+ count += 1 if (test[:failures].to_i + test[:errors].to_i > 0) || test[:time].nil?
108
+ count
109
+ end
110
+
111
+ log "\n"
112
+ log "".ljust(100, "=")
113
+ log "#{section} tests (#{failures} failures in #{data.finish - data.start} seconds)"
114
+ suit_tests.each do |test|
115
+ log "" .ljust(100, "-")
116
+ log " Description".ljust(16 , ".") + ": #{description test}"
117
+ log " Duration" .ljust(16 , ".") + ": #{test[:time] }"
118
+ log " Summary" .ljust(16 , ".") + ": #{test[:summary] }"
119
+ end
120
+ log "".ljust(100, "=")
121
+ log "\n"
122
+ end
123
+
124
+ def extract_test_results(data)
125
+ [{}].tap do |result|
126
+ data.output.each do |line|
127
+ if line.match(DESCRIPTION_MATCH) || line.match(GEM_SUIT_MATCH)
128
+ result.last[:description] = $1
129
+ end
130
+ if line.match(LOAD_MATCH)
131
+ result.last[:load] = "Rails #{$1} - #{camelize $2}"
132
+ end
133
+ if line.match(TIME_MATCH)
134
+ result.last[:time] = $1
135
+ end
136
+ if line.match(SUMMARY_MATCH)
137
+ result.last[:summary ] = line
138
+ result.last[$2.to_sym] = $1
139
+ result.last[$4.to_sym] = $3
140
+ result.last[$6.to_sym] = $5
141
+ result.last[$8.to_sym] = $7
142
+ result << {}
143
+ end
144
+ end
145
+
146
+ result.reject!{|x| x.empty?}
147
+ end
148
+ end
149
+
150
+ def description(test)
151
+ failed = (test[:failures].to_i + test[:errors].to_i > 0) || test[:tests].nil?
152
+ ((test[:description] unless (test[:description] || "").empty?) || test[:load]).send failed ? :red : :green
153
+ end
154
+
155
+ end
156
+
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,41 @@
1
+ require "thor/shell/basic"
2
+
3
+ module GemSuit
4
+ class CLI < Thor
5
+ module Base
6
+ module Shell
7
+
8
+ def self.included(base)
9
+ base.send :include, InstanceMethods
10
+ end
11
+
12
+ module InstanceMethods
13
+
14
+ def shell
15
+ @shell ||= Thor::Shell::Basic.new
16
+ end
17
+
18
+ def is?(*args)
19
+ shell.send :is?, *args
20
+ end
21
+
22
+ def agree?(question, default = nil)
23
+ opts = %w(y n).collect{|x| !default.nil? && x =~ is?(default) ? x.upcase : x}
24
+ answer = ask question, opts, default
25
+ !!(answer =~ is?(:yes))
26
+ end
27
+
28
+ def ask(question, opts = nil, default = nil)
29
+ in_brackets = [opts, default].compact.first
30
+ statement = [question, ("[#{in_brackets}]" unless in_brackets.nil?)].compact.join " "
31
+
32
+ answer = shell.ask statement if options.interactive? || default.nil?
33
+ answer.nil? || answer.empty? ? default.to_s : answer
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,83 @@
1
+ STDOUT.sync = true
2
+
3
+ module GemSuit
4
+ class CLI < Thor
5
+ module Base
6
+ module Utils
7
+
8
+ def self.included(base)
9
+ base.send :include, InstanceMethods
10
+ end
11
+
12
+ module InstanceMethods
13
+
14
+ def execute(command, force = nil)
15
+ options.very_verbose? || options.verbose? || force ? system(command) : `#{command}`
16
+ end
17
+
18
+ def log(string, force = false)
19
+ puts string if options.very_verbose? || options.verbose? || force
20
+ end
21
+
22
+ def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
23
+ if first_letter_in_uppercase
24
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
25
+ else
26
+ lower_case_and_underscored_word.to_s[0].chr.downcase + camelize(lower_case_and_underscored_word)[1..-1]
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def assert_gem_dir(non_gemsuit = false)
33
+ if Dir["*.gemspec"].empty?
34
+ raise Error, "Missing *.gemspec in current directory. Is this really a gem directory?"
35
+ end
36
+ if non_gemsuit && !Dir[".suit"].empty?
37
+ raise Error, "Found .suit in current directory. Is this gem already provided with GemSuit?"
38
+ end
39
+ end
40
+
41
+ def assert_suit_dir
42
+ assert_gem_dir
43
+ if Dir[".suit"].empty?
44
+ raise Error, "Missing .suit in current directory. Is this really a GemSuit directory?"
45
+ end
46
+ end
47
+
48
+ def assert_rails_dir
49
+ unless File.expand_path("").match /suit\/rails-\d\/dummy$/
50
+ raise Error, "Current directory path does not match \"/suit/rails-{2,3}/dummy\". Is this really a GemSuit dummy app?"
51
+ end
52
+ end
53
+
54
+ def major_rails_versions
55
+ Dir["suit/rails-*"].collect{|dir| dir.match(/rails-(\d)/); $1}
56
+ end
57
+
58
+ def gem_name
59
+ File.basename File.expand_path("")
60
+ end
61
+
62
+ def suit_gem_path
63
+ File.expand_path "../../../../..", __FILE__
64
+ end
65
+
66
+ def templates_path
67
+ File.expand_path "templates", suit_gem_path
68
+ end
69
+
70
+ def static_templates_path
71
+ File.expand_path "static", templates_path
72
+ end
73
+
74
+ def dynamic_templates_path
75
+ File.expand_path "dynamic", templates_path
76
+ end
77
+
78
+ end
79
+
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,15 @@
1
+ require "gem_suit/cli/base/utils"
2
+ require "gem_suit/cli/base/shell"
3
+
4
+ module GemSuit
5
+ class CLI < Thor
6
+ module Base
7
+
8
+ def self.included(base)
9
+ base.send :include, CLI::Base::Utils
10
+ base.send :include, CLI::Base::Shell
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ class Rails::Boot
2
+ def run
3
+ load_initializer
4
+
5
+ Rails::Initializer.class_eval do
6
+ def load_gems
7
+ @bundler_loaded ||= Bundler.require :default, Rails.env
8
+ end
9
+ end
10
+
11
+ Rails::Initializer.run(:set_load_path)
12
+ end
13
+ end
14
+
@@ -0,0 +1,154 @@
1
+ require "fileutils"
2
+ require "thor"
3
+ require "gem_suit/cli/base"
4
+
5
+ module GemSuit
6
+ class CLI < Thor
7
+ module Builder
8
+
9
+ class Generator < Thor
10
+ include Thor::Actions
11
+ include Base
12
+
13
+ def initialize(builder)
14
+ @builder = builder
15
+ self.class.source_root = dynamic_templates_path
16
+ self.destination_root = root
17
+ end
18
+
19
+ no_tasks do
20
+ def run
21
+ create_symlinks
22
+ generate
23
+ stage_files
24
+ end
25
+
26
+ def options
27
+ @builder.options
28
+ end
29
+
30
+ def suit_config
31
+ @builder.suit_config
32
+ end
33
+
34
+ def locals
35
+ @locals ||= {}
36
+ end
37
+ end
38
+
39
+ class << self
40
+ def source_root
41
+ @source_root
42
+ end
43
+
44
+ def source_root=(path)
45
+ @source_root = path
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def method_missing(method, *args)
52
+ if locals.include?(method)
53
+ locals[method]
54
+ else
55
+ super
56
+ end
57
+ end
58
+
59
+ def root
60
+ File.expand_path ""
61
+ end
62
+
63
+ def changelog?
64
+ !Dir["CHANGELOG*"].empty?
65
+ end
66
+
67
+ def mit_licensed?
68
+ !Dir["MIT-LICENSE*"].empty?
69
+ end
70
+
71
+ def read_me?
72
+ !Dir["README*"].empty?
73
+ end
74
+
75
+ def create_symlinks
76
+ rails_root = Dir["suit/rails-*/dummy"].max
77
+ FileUtils.rm File.expand_path("public/index.html", rails_root)
78
+ FileUtils.cp_r File.expand_path("public", rails_root), "suit/shared"
79
+
80
+ Dir["suit/rails-*/dummy"].each do |rails_root|
81
+ %w(app/models
82
+ app/views
83
+ db/schema.rb
84
+ db/seeds.rb
85
+ public
86
+ test).each do |relative_path|
87
+
88
+ path = File.expand_path relative_path, rails_root
89
+
90
+ if File.exists? path
91
+ method = File.directory?(path) ? :rm_rf : :rm
92
+ FileUtils.send method, path
93
+ end
94
+
95
+ prefix = ([".."] * relative_path.split("/").size).join("/")
96
+ create_link path, "#{prefix}/../shared/#{relative_path}", :verbose => false
97
+ end
98
+ end
99
+ end
100
+
101
+ def generate
102
+ if options.extras?
103
+ template "CHANGELOG.rdoc", :verbose => false unless changelog?
104
+
105
+ unless mit_licensed? || !agree?("Do you want to use a MIT-LICENSE?", :yes)
106
+ locals[:author] ||= ask "What is your author name?"
107
+ template "MIT-LICENSE", :verbose => false
108
+ end
109
+
110
+ unless read_me?
111
+ locals[:twitter] ||= ask "What is your Twitter name?"
112
+ locals[:email] ||= ask "What is your email address?"
113
+ locals[:author] ||= ask "What is your author name?"
114
+ template "README.textile", :verbose => false
115
+ end
116
+ end
117
+
118
+ Dir["suit/rails-*/dummy"].each do |rails_root|
119
+ file = File.expand_path("config/routes.rb", rails_root)
120
+ routes = File.readlines file
121
+ routes.each_with_index do |line, index|
122
+ next unless line.match "to delete public/index.html"
123
+ routes[index + 1] = routes[index + 1].gsub("# ", "").gsub("welcome", "application")
124
+ break
125
+ end
126
+ File.open file, "w" do |file|
127
+ file << routes
128
+ end
129
+ end
130
+
131
+ gemspec = File.read "#{gem_name}.gemspec"
132
+ gemspec.gsub! "TODO: Write your email address", email unless locals[:email ].to_s.empty?
133
+ gemspec.gsub! "TODO: Write your name" , author unless locals[:author].to_s.empty?
134
+ File.open "#{gem_name}.gemspec", "w" do |file|
135
+ file << gemspec
136
+ end
137
+
138
+ template "suit/shared/app/views/application/index.html.erb", :verbose => false
139
+ template "suit/shared/public/stylesheets/app.css", :force => true, :verbose => false
140
+ template "suit/shared/test/test_helper.rb", :verbose => false
141
+ template "suit/templates/shared/Gemfile", :verbose => false
142
+ template "suit/templates/shared/config/database-#{suit_config[:mysql] ? "mysql" : "sqlite"}.yml", "suit/templates/shared/config/database.yml", :verbose => false
143
+ end
144
+
145
+ def stage_files
146
+ template "gitignore", ".gitignore", :force => true, :verbose => false
147
+ execute "git add -A"
148
+ end
149
+
150
+ end
151
+
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,146 @@
1
+ require "thor"
2
+ require "gem_suit/cli/base"
3
+
4
+ module GemSuit
5
+ class CLI < Thor
6
+ module Builder
7
+
8
+ class RailsApp < Thor
9
+ include Thor::Actions
10
+ include Base
11
+
12
+ def initialize(version_spec, builder, confirm = true)
13
+ @version_spec = version_spec
14
+ @builder = builder
15
+ self.class.source_root = dynamic_templates_path
16
+ confirm_version if confirm
17
+ end
18
+
19
+ no_tasks do
20
+ def install
21
+ confirm_version
22
+ generate
23
+ bundle
24
+ create_gemfile
25
+ end
26
+
27
+ def options
28
+ @builder.options
29
+ end
30
+
31
+ def rails_gem_version
32
+ version
33
+ end
34
+ end
35
+
36
+ class << self
37
+ def source_root
38
+ @source_root
39
+ end
40
+
41
+ def source_root=(path)
42
+ @source_root = path
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def expand_version_spec
49
+ @version_spec == "latest" ? latest : @version_spec
50
+ end
51
+
52
+ def latest
53
+ [`rails -v`.match(/\d\.\d+\.\d+/).to_s, "3.0.6"].max
54
+ end
55
+
56
+ def target_dir
57
+ File.expand_path "suit/rails-#{version(:major)}"
58
+ end
59
+
60
+ def rails_root
61
+ File.expand_path("dummy", target_dir)
62
+ end
63
+
64
+ def generate_cmd
65
+ "rails #{version(:major) < 3 ? "_#{version}_" : "new"} dummy"
66
+ end
67
+
68
+ def version(segment = nil)
69
+ return @version if segment.nil?
70
+
71
+ segments = @version.match(/(\d+)\.(\d+)\.(\d+)/).captures.collect &:to_i
72
+ case segment
73
+ when :major
74
+ segments[0]
75
+ when :minor
76
+ segments[1]
77
+ when :patch
78
+ segments[2]
79
+ end
80
+ end
81
+
82
+ def valid_version?
83
+ !!version.match(/^\d+\.\d+\.\d+$/)
84
+ end
85
+
86
+ def bundled?
87
+ !Dir[File.expand_path("Gemfile", destination_root)].empty?
88
+ end
89
+
90
+ def confirm_version
91
+ return if @confirmed_version
92
+
93
+ @version = expand_version_spec
94
+ answer = ask "Generate Rails #{version(:major)} application? You can specify another version or use 'n' to skip", version, version
95
+ if answer =~ is?(:no)
96
+ @version = nil
97
+ return
98
+ end
99
+ @version = answer unless answer.empty?
100
+
101
+ self.destination_root = rails_root
102
+ @confirmed_version = true
103
+ end
104
+
105
+ def generate
106
+ unless valid_version?
107
+ log "Cannot generate Rails application with specified version #{version.inspect}".red
108
+ return
109
+ end
110
+
111
+ if File.exists? target_dir
112
+ log "Already installed a Rails #{version(:major)} application (skipping #{version})".red, true
113
+ return
114
+ end
115
+
116
+ unless `gem list rails -i -v #{version}`.strip == "true"
117
+ log "Installing Rails #{version} (this can take a while)".yellow, true
118
+ execute "gem install rails -v=#{version}"
119
+ end
120
+
121
+ FileUtils.mkdir target_dir
122
+ log "Generating Rails #{version(:major)} application"
123
+ log generate_cmd
124
+ execute "cd #{target_dir} && #{generate_cmd}"
125
+ end
126
+
127
+ def bundle
128
+ unless valid_version?
129
+ log "Cannot bundle Rails application with specified version #{version.inspect}".red
130
+ return
131
+ end
132
+
133
+ return if bundled?
134
+
135
+ insert_into_file "config/boot.rb", File.read(File.expand_path("../boot", __FILE__)), :before => "# All that for this:\n", :verbose => false
136
+ template "config/preinitializer.rb", :verbose => false
137
+ end
138
+
139
+ def create_gemfile
140
+ template "Gemfile", :force => true, :verbose => false
141
+ end
142
+ end
143
+
144
+ end
145
+ end
146
+ end