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.
- data/.gitignore +10 -0
- data/.suit +4 -0
- data/CHANGELOG.rdoc +5 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +20 -0
- data/README.textile +419 -0
- data/Rakefile +26 -0
- data/VERSION +1 -0
- data/bin/suit +10 -0
- data/gem_suit.gemspec +26 -0
- data/lib/gem_suit/application/actions.rb +203 -0
- data/lib/gem_suit/application/test.rb +106 -0
- data/lib/gem_suit/application/utils/gemfile.rb +42 -0
- data/lib/gem_suit/application/utils.rb +135 -0
- data/lib/gem_suit/application.rb +42 -0
- data/lib/gem_suit/cli/application/io_buffer.rb +54 -0
- data/lib/gem_suit/cli/application/test_loader.rb +5 -0
- data/lib/gem_suit/cli/application.rb +159 -0
- data/lib/gem_suit/cli/base/shell.rb +41 -0
- data/lib/gem_suit/cli/base/utils.rb +83 -0
- data/lib/gem_suit/cli/base.rb +15 -0
- data/lib/gem_suit/cli/builder/boot +14 -0
- data/lib/gem_suit/cli/builder/generator.rb +154 -0
- data/lib/gem_suit/cli/builder/rails_app.rb +146 -0
- data/lib/gem_suit/cli/builder.rb +143 -0
- data/lib/gem_suit/cli/config/hash.rb +61 -0
- data/lib/gem_suit/cli/config.rb +37 -0
- data/lib/gem_suit/cli.rb +145 -0
- data/lib/gem_suit/integration_test.rb +14 -0
- data/lib/gem_suit/test_help.rb +17 -0
- data/lib/gem_suit/version.rb +9 -0
- data/lib/gem_suit.rb +6 -0
- data/templates/dynamic/CHANGELOG.rdoc +5 -0
- data/templates/dynamic/Gemfile +14 -0
- data/templates/dynamic/MIT-LICENSE +20 -0
- data/templates/dynamic/README.textile +35 -0
- data/templates/dynamic/VERSION +1 -0
- data/templates/dynamic/config/boot.rb +13 -0
- data/templates/dynamic/config/preinitializer.rb +20 -0
- data/templates/dynamic/gitignore +9 -0
- data/templates/dynamic/suit/shared/app/views/application/index.html.erb +16 -0
- data/templates/dynamic/suit/shared/public/stylesheets/app.css +99 -0
- data/templates/dynamic/suit/shared/test/test_helper.rb +37 -0
- data/templates/dynamic/suit/templates/shared/Gemfile +14 -0
- data/templates/dynamic/suit/templates/shared/config/database-mysql.yml +11 -0
- data/templates/dynamic/suit/templates/shared/config/database-sqlite.yml +10 -0
- data/templates/static/suit/shared/app/models/.gitkeep +0 -0
- data/templates/static/suit/shared/app/views/layouts/application.html.erb +11 -0
- data/templates/static/suit/shared/db/schema.rb +2 -0
- data/templates/static/suit/shared/db/seeds.rb +7 -0
- data/templates/static/suit/shared/test/fixtures/.gitkeep +0 -0
- data/templates/static/suit/shared/test/integration/suit/example.rb +40 -0
- data/templates/static/suit/shared/test/suit_application/capybara_extensions.rb +36 -0
- data/templates/static/suit/shared/test/suit_application.rb +27 -0
- data/templates/static/suit/shared/test/unit/.gitkeep +0 -0
- data/templates/static/suit/templates/shared/config/initializers/.gitkeep +0 -0
- data/templates/static/suit/templates/shared/db/schema.rb +2 -0
- metadata +188 -0
@@ -0,0 +1,203 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "rich/support/core/string/colorize"
|
3
|
+
require "gem_suit/application/utils"
|
4
|
+
|
5
|
+
module GemSuit
|
6
|
+
class Application < ::Thor::Group
|
7
|
+
module Actions
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
base.extend ClassMethods
|
11
|
+
base.send :include, Utils
|
12
|
+
base.send :include, InstanceMethods
|
13
|
+
base.send :include, Thor::Actions
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def restore_all
|
18
|
+
self.new.restore_all true
|
19
|
+
end
|
20
|
+
|
21
|
+
def stash_all
|
22
|
+
self.new.stash_all
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module InstanceMethods
|
27
|
+
attr_accessor :config, :verbose
|
28
|
+
|
29
|
+
def restore_files
|
30
|
+
# Implement in subclass
|
31
|
+
end
|
32
|
+
|
33
|
+
def stash_files
|
34
|
+
# Implement in subclass
|
35
|
+
end
|
36
|
+
|
37
|
+
def locals_for_template(path)
|
38
|
+
# Implement in subclass
|
39
|
+
end
|
40
|
+
|
41
|
+
def config
|
42
|
+
@config || {}
|
43
|
+
end
|
44
|
+
|
45
|
+
def locals
|
46
|
+
@locals ||= (locals_for_template @relative_path if @relative_path) || {}
|
47
|
+
end
|
48
|
+
|
49
|
+
def restore_all(force = nil)
|
50
|
+
if @prepared
|
51
|
+
unless force
|
52
|
+
log "Cannot (non-forced) restore files after having prepared the test application" unless force.nil?
|
53
|
+
return
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
return if restore_files == false
|
58
|
+
|
59
|
+
if File.exists?(new_files = expand_path(".new_files"))
|
60
|
+
File.readlines(new_files).each do |line|
|
61
|
+
delete line.strip
|
62
|
+
end
|
63
|
+
File.delete new_files
|
64
|
+
end
|
65
|
+
|
66
|
+
restore "app/models/**/*.#{STASHED_EXT}"
|
67
|
+
restore "app/views/**/*.#{STASHED_EXT}"
|
68
|
+
restore "db/**/*.#{STASHED_EXT}"
|
69
|
+
restore "public/**/*.#{STASHED_EXT}"
|
70
|
+
restore "test/**/*.#{STASHED_EXT}"
|
71
|
+
restore "**/*.#{STASHED_EXT}"
|
72
|
+
true
|
73
|
+
end
|
74
|
+
|
75
|
+
def stash_all
|
76
|
+
return if stash_files == false
|
77
|
+
stash "Gemfile.lock"
|
78
|
+
["shared", "rails-#{rails_version}"].each do |dir|
|
79
|
+
dir_path = File.expand_path dir, templates_path
|
80
|
+
next unless File.exists? dir_path
|
81
|
+
root = Pathname.new dir_path
|
82
|
+
Dir[File.expand_path("**/*", root.realpath)].each do |file|
|
83
|
+
next if File.directory? file
|
84
|
+
path = Pathname.new file
|
85
|
+
write path.relative_path_from(root).to_s
|
86
|
+
end
|
87
|
+
end
|
88
|
+
true
|
89
|
+
end
|
90
|
+
|
91
|
+
def skip(action, string)
|
92
|
+
((@skipped_files ||= {})[action] ||= []) << string
|
93
|
+
end
|
94
|
+
|
95
|
+
def skip?(action, string)
|
96
|
+
return false if @skipped_files.nil? || @skipped_files[action].nil?
|
97
|
+
!!@skipped_files[action].detect{|x| File.fnmatch? expand_path(x), string}
|
98
|
+
end
|
99
|
+
|
100
|
+
def restore(string)
|
101
|
+
Dir[expand_path(string)].each do |file|
|
102
|
+
next unless File.exists? stashed(file)
|
103
|
+
next if skip? :restore, file
|
104
|
+
delete original(file)
|
105
|
+
log :restoring, stashed(file)
|
106
|
+
File.rename stashed(file), original(file)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def delete(string)
|
111
|
+
Dir[expand_path(string)].each do |file|
|
112
|
+
next if skip? :deleting, file
|
113
|
+
log :deleting, file
|
114
|
+
File.delete file
|
115
|
+
end
|
116
|
+
|
117
|
+
dirname = expand_path File.dirname(string)
|
118
|
+
return unless File.exists?(dirname)
|
119
|
+
|
120
|
+
Dir.glob("#{dirname}/*", File::FNM_DOTMATCH) do |file|
|
121
|
+
return unless %w(. ..).include? File.basename(file)
|
122
|
+
end
|
123
|
+
|
124
|
+
log :deleting, dirname
|
125
|
+
Dir.delete dirname
|
126
|
+
end
|
127
|
+
|
128
|
+
def write(string)
|
129
|
+
return if skip? :write, string
|
130
|
+
stash string
|
131
|
+
create string
|
132
|
+
end
|
133
|
+
|
134
|
+
def stash(string)
|
135
|
+
Dir[expand_path(string)].each do |file|
|
136
|
+
next if new_file?(file) || File.exists?(stashed(file))
|
137
|
+
next if skip? :stash, file
|
138
|
+
log :stashing, original(file)
|
139
|
+
File.rename original(file), stashed(file)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def create(string)
|
144
|
+
new_files = []
|
145
|
+
|
146
|
+
["shared", "rails-#{rails_version}"].each do |dir|
|
147
|
+
path = File.expand_path dir, templates_path
|
148
|
+
next unless File.exists? path
|
149
|
+
root = Pathname.new path
|
150
|
+
Dir[File.expand_path(string, root.realpath)].each do |file|
|
151
|
+
next if File.directory? file
|
152
|
+
next if skip? :create, file
|
153
|
+
begin
|
154
|
+
@relative_path = Pathname.new(file).relative_path_from(root).to_s
|
155
|
+
@locals = nil
|
156
|
+
new_files << @relative_path unless new_file?(expand_path(@relative_path)) || File.exists?(stashed(@relative_path))
|
157
|
+
log :creating, expand_path(@relative_path)
|
158
|
+
template file, expand_path(@relative_path), :verbose => false
|
159
|
+
ensure
|
160
|
+
@relative_path = nil
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
unless new_files.empty?
|
166
|
+
File.open(expand_path(".new_files"), "a") do |file|
|
167
|
+
file << new_files.collect{|x| "#{x}\n"}.join("")
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def copy(source, destination)
|
173
|
+
log :copying, "#{source} -> #{destination}"
|
174
|
+
FileUtils.cp expand_path(source), expand_path(destination)
|
175
|
+
end
|
176
|
+
|
177
|
+
def generate(*args)
|
178
|
+
return if skip? :generate, args.first
|
179
|
+
command = case rails_version
|
180
|
+
when 2
|
181
|
+
"script/generate"
|
182
|
+
when 3
|
183
|
+
"rails g"
|
184
|
+
end
|
185
|
+
|
186
|
+
execute "#{command} #{args.join(" ")}"
|
187
|
+
@ran_generator = true
|
188
|
+
end
|
189
|
+
|
190
|
+
private
|
191
|
+
|
192
|
+
def method_missing(method, *args)
|
193
|
+
if locals.include? method
|
194
|
+
locals[method]
|
195
|
+
else
|
196
|
+
super
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module GemSuit
|
2
|
+
class Application < ::Thor::Group
|
3
|
+
module Test
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
base.send :include, InstanceMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def create_test_database
|
12
|
+
self.new.create_test_database
|
13
|
+
end
|
14
|
+
|
15
|
+
def setup(*args)
|
16
|
+
self.new.setup *args
|
17
|
+
end
|
18
|
+
|
19
|
+
def test(*args)
|
20
|
+
self.new.test *args
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module InstanceMethods
|
25
|
+
attr_accessor :config, :verbose
|
26
|
+
|
27
|
+
def description
|
28
|
+
# Implement in subclass
|
29
|
+
end
|
30
|
+
|
31
|
+
def prepare
|
32
|
+
# Implement in subclass
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_test_database
|
36
|
+
write "config/database.yml"
|
37
|
+
execute "RAILS_ENV=test rake db:create"
|
38
|
+
ensure
|
39
|
+
restore "**/*.#{STASHED_EXT}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def setup(config = {})
|
43
|
+
@skipped_files = nil
|
44
|
+
@config = config
|
45
|
+
|
46
|
+
log "\n".ljust 145, "="
|
47
|
+
log "Setting up test environment for Rails #{[rails_version, description].compact.join(" - ")}\n"
|
48
|
+
log "\n".rjust 145, "="
|
49
|
+
|
50
|
+
restore_all
|
51
|
+
stash_all
|
52
|
+
bundle_install
|
53
|
+
|
54
|
+
prepare
|
55
|
+
prepare_database
|
56
|
+
@prepared = true
|
57
|
+
end
|
58
|
+
|
59
|
+
def test(config = {})
|
60
|
+
setup config
|
61
|
+
|
62
|
+
log "\n".rjust 145, "="
|
63
|
+
log "Environment for Rails #{[rails_version, description].compact.join(" - ")} is ready for testing"
|
64
|
+
log "=" .ljust 144, "="
|
65
|
+
|
66
|
+
run_environment
|
67
|
+
end
|
68
|
+
|
69
|
+
def prepare_database
|
70
|
+
return if @db_prepared
|
71
|
+
if @ran_generator
|
72
|
+
stash "db/schema.rb"
|
73
|
+
execute "rake db:test:purge"
|
74
|
+
execute "RAILS_ENV=test rake db:migrate"
|
75
|
+
else
|
76
|
+
execute "rake db:test:load"
|
77
|
+
end
|
78
|
+
@db_prepared = true
|
79
|
+
end
|
80
|
+
|
81
|
+
def run_environment
|
82
|
+
ENV["RAILS_ENV"] = "test"
|
83
|
+
|
84
|
+
require File.expand_path("config/environment.rb", root_path)
|
85
|
+
require "#{"rails/" if Rails::VERSION::MAJOR >= 3}test_help"
|
86
|
+
|
87
|
+
begin
|
88
|
+
require "gem_suit/integration_test"
|
89
|
+
rescue LoadError
|
90
|
+
gem_suit_path = File.expand_path "../../..", __FILE__
|
91
|
+
$:.unshift gem_suit_path
|
92
|
+
require "gem_suit/integration_test"
|
93
|
+
end
|
94
|
+
|
95
|
+
Dir[File.expand_path("../#{File.basename(self.class.__file__, ".rb")}/**/*.rb", self.class.__file__)].each do |file|
|
96
|
+
next if skip? :require, file
|
97
|
+
require file
|
98
|
+
end
|
99
|
+
|
100
|
+
log "\nRunning Rails #{Rails::VERSION::STRING}\n\n"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module GemSuit
|
2
|
+
class Application < ::Thor::Group
|
3
|
+
module Utils
|
4
|
+
class Gemfile
|
5
|
+
|
6
|
+
# A simple class which derives a Gemfile
|
7
|
+
|
8
|
+
attr_accessor :source
|
9
|
+
|
10
|
+
def initialize(*files)
|
11
|
+
@files = files
|
12
|
+
end
|
13
|
+
|
14
|
+
def gems
|
15
|
+
@gems ||= begin
|
16
|
+
@gems = {}
|
17
|
+
gem_file = @files.detect{|file| File.exists? file}
|
18
|
+
gem_specs = File.readlines(gem_file).join "\n"
|
19
|
+
instance_eval gem_specs
|
20
|
+
gems
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def source(src)
|
25
|
+
source = src
|
26
|
+
end
|
27
|
+
|
28
|
+
def gem(name, *args)
|
29
|
+
options = (args.pop if args.last.is_a?(Hash)) || {}
|
30
|
+
options[:version] = args.first if args.first.is_a?(String)
|
31
|
+
@gems[name] = options
|
32
|
+
end
|
33
|
+
|
34
|
+
def method_missing(method, *args)
|
35
|
+
# e.g. group :test do
|
36
|
+
# end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
STDOUT.sync = true
|
2
|
+
|
3
|
+
require "gem_suit/application/utils/gemfile"
|
4
|
+
|
5
|
+
module GemSuit
|
6
|
+
class Application < ::Thor::Group
|
7
|
+
module Utils
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
base.extend ClassMethods
|
11
|
+
base.send :include, InstanceMethods
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
attr_accessor :__file__
|
16
|
+
|
17
|
+
def inherited(klass)
|
18
|
+
klass.__file__ = caller.first[/^[^:]+/]
|
19
|
+
end
|
20
|
+
|
21
|
+
def bundle_install
|
22
|
+
self.new.bundle_install
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module InstanceMethods
|
27
|
+
attr_accessor :root_path, :validate_root_path
|
28
|
+
|
29
|
+
def bundle_install
|
30
|
+
return unless bundle_install?
|
31
|
+
if verbose
|
32
|
+
execute "bundle install", "(this can take several minutes...)"
|
33
|
+
else
|
34
|
+
puts "Running `bundle install` (this can take several minutes...)".yellow
|
35
|
+
puts "(in #{root_path})"
|
36
|
+
`cd #{root_path} && bundle install`
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def bundle_install?
|
41
|
+
`cd #{root_path} && bundle check`.any?{|line| line.include? "`bundle install`"}
|
42
|
+
end
|
43
|
+
|
44
|
+
def validate_root_path!(path)
|
45
|
+
unless path.match(/rails-\d/)
|
46
|
+
log "Running a #{self.class.name} instance from an invalid path: '#{path}' needs to match ".red + "/rails-\\d/".yellow
|
47
|
+
exit
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def root_path
|
52
|
+
(@root_path || (Rails.root if defined? Rails) || begin
|
53
|
+
dir = File.expand_path "../..", self.class.__file__
|
54
|
+
File.exists?("#{dir}/config/environment.rb") ? dir : Dir[File.expand_path("#{dir}/../rails-*/dummy")].last
|
55
|
+
end).to_s.tap do |path|
|
56
|
+
validate_root_path! path if validate_root_path
|
57
|
+
self.class.source_root = path
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def shared_path
|
62
|
+
File.expand_path("../../shared", root_path)
|
63
|
+
end
|
64
|
+
|
65
|
+
def templates_path
|
66
|
+
File.expand_path("../../templates", root_path)
|
67
|
+
end
|
68
|
+
|
69
|
+
def expand_path(path)
|
70
|
+
Pathname.new(path).absolute? ?
|
71
|
+
path :
|
72
|
+
File.expand_path(path, root_path)
|
73
|
+
end
|
74
|
+
|
75
|
+
def original(file)
|
76
|
+
expand_path file.gsub(/\.#{STASHED_EXT}$/, "")
|
77
|
+
end
|
78
|
+
|
79
|
+
def stashed(file)
|
80
|
+
expand_path file.match(/\.#{STASHED_EXT}$/) ? file : "#{file}.#{STASHED_EXT}"
|
81
|
+
end
|
82
|
+
|
83
|
+
def new_file?(file)
|
84
|
+
return false unless File.exists? expand_path(".new_files")
|
85
|
+
root = Pathname.new root_path
|
86
|
+
relative_path = Pathname.new(file).relative_path_from(root).to_s
|
87
|
+
File.readlines(expand_path(".new_files")).any?{|line| line.strip == relative_path}
|
88
|
+
end
|
89
|
+
|
90
|
+
def rails_version
|
91
|
+
root_path.match(/\/rails-(\d)\//)[1].to_i
|
92
|
+
end
|
93
|
+
|
94
|
+
def rails_gem_version
|
95
|
+
case rails_version
|
96
|
+
when 2
|
97
|
+
File.readlines(expand_path("config/environment.rb")).each do |line|
|
98
|
+
match = line.match /RAILS_GEM_VERSION\s*=\s*["']([\d\.]+)["']/
|
99
|
+
return $1 if match
|
100
|
+
end
|
101
|
+
when 3
|
102
|
+
files = [expand_path(stashed("Gemfile")), expand_path("Gemfile")]
|
103
|
+
Gemfile.new(*files).gems["rails"][:version]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def mysql_password
|
108
|
+
file = File.expand_path("mysql", shared_path)
|
109
|
+
"#{File.new(file).read}".strip if File.exists? file
|
110
|
+
end
|
111
|
+
|
112
|
+
def execute(command, text = "")
|
113
|
+
return if command.to_s.gsub(/\s/, "").size == 0
|
114
|
+
log :executing, "#{command} #{text}"
|
115
|
+
`cd #{root_path} && #{command}`
|
116
|
+
end
|
117
|
+
|
118
|
+
def log(action, string_or_force = nil, force = nil)
|
119
|
+
if %w(TrueClass FalseClass).include? string_or_force.class.name
|
120
|
+
string = nil
|
121
|
+
force = string_or_force
|
122
|
+
else
|
123
|
+
string = string_or_force
|
124
|
+
force = false
|
125
|
+
end
|
126
|
+
return unless verbose || force
|
127
|
+
output = [string || action]
|
128
|
+
output.unshift action.to_s.capitalize.ljust(10, " ") unless string.nil?
|
129
|
+
puts output.join(" ")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "optparse"
|
2
|
+
require "thor/group"
|
3
|
+
require "gem_suit/application/actions"
|
4
|
+
require "gem_suit/application/test"
|
5
|
+
|
6
|
+
module GemSuit
|
7
|
+
class Application < ::Thor::Group
|
8
|
+
|
9
|
+
include Application::Actions
|
10
|
+
include Application::Test
|
11
|
+
|
12
|
+
STASHED_EXT = "stashed"
|
13
|
+
|
14
|
+
def initialize(options = {:validate_root_path => true})
|
15
|
+
super [], {}, {}
|
16
|
+
|
17
|
+
begin
|
18
|
+
OptionParser.new do |opts|
|
19
|
+
opts.on "-v", "--[no-]verbose" do |v|
|
20
|
+
options[:verbose] ||= v
|
21
|
+
end
|
22
|
+
end.parse! ARGV
|
23
|
+
rescue OptionParser::InvalidOption
|
24
|
+
end
|
25
|
+
|
26
|
+
options.each do |key, value|
|
27
|
+
send :"#{key}=", value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class << self
|
32
|
+
def source_root
|
33
|
+
@source_root
|
34
|
+
end
|
35
|
+
|
36
|
+
def source_root=(path)
|
37
|
+
@source_root = path
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module GemSuit
|
2
|
+
class CLI < Thor
|
3
|
+
module Application
|
4
|
+
class IOBuffer
|
5
|
+
|
6
|
+
def self.capture(&block)
|
7
|
+
self.new.capture &block
|
8
|
+
end
|
9
|
+
|
10
|
+
def capture(&block)
|
11
|
+
@data = nil
|
12
|
+
data.record do
|
13
|
+
yield self
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def log(line)
|
18
|
+
data << "GemSuit: #{line}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def execute(command)
|
22
|
+
IO.popen(command) do |io|
|
23
|
+
until io.eof?
|
24
|
+
puts (data << io.gets).last
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def data
|
32
|
+
@data ||= BufferData.new
|
33
|
+
end
|
34
|
+
|
35
|
+
class BufferData
|
36
|
+
attr_reader :output, :start, :finish
|
37
|
+
|
38
|
+
def record(&block)
|
39
|
+
@output = []
|
40
|
+
@start = Time.now
|
41
|
+
yield
|
42
|
+
@finish = Time.now
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def <<(string)
|
47
|
+
@output << string
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|