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