ing 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/GENERATORS.md +2 -0
- data/LICENSE +18 -0
- data/OPTIONS.md +2 -0
- data/README.md +251 -0
- data/TASKS.md +21 -0
- data/bin/ing +5 -0
- data/examples/rspec_convert.rb +102 -0
- data/ing.gemspec +29 -0
- data/ing.rb +102 -0
- data/lib/ing.rb +78 -0
- data/lib/ing/actions/create_file.rb +105 -0
- data/lib/ing/actions/create_link.rb +57 -0
- data/lib/ing/actions/directory.rb +98 -0
- data/lib/ing/actions/empty_directory.rb +155 -0
- data/lib/ing/actions/file_manipulation.rb +308 -0
- data/lib/ing/actions/inject_into_file.rb +109 -0
- data/lib/ing/commands/boot.rb +76 -0
- data/lib/ing/commands/generate.rb +64 -0
- data/lib/ing/commands/help.rb +87 -0
- data/lib/ing/commands/implicit.rb +59 -0
- data/lib/ing/commands/list.rb +108 -0
- data/lib/ing/dispatcher.rb +132 -0
- data/lib/ing/files.rb +190 -0
- data/lib/ing/lib_trollop.rb +782 -0
- data/lib/ing/shell.rb +390 -0
- data/lib/ing/trollop/parser.rb +17 -0
- data/lib/ing/util.rb +61 -0
- data/lib/ing/version.rb +3 -0
- data/lib/thor/actions/file_manipulation.rb +30 -0
- data/lib/thor/shell/basic.rb +44 -0
- data/test/acceptance/ing_run_tests.rb +164 -0
- data/test/actions/create_file_spec.rb +209 -0
- data/test/actions/create_link_spec.rb +90 -0
- data/test/actions/directory_spec.rb +167 -0
- data/test/actions/empty_directory_spec.rb +146 -0
- data/test/actions/file_manipulation_spec.rb +433 -0
- data/test/actions/inject_into_file_spec.rb +147 -0
- data/test/fixtures/application.rb +2 -0
- data/test/fixtures/app{1}/README +3 -0
- data/test/fixtures/bundle/execute.rb +6 -0
- data/test/fixtures/bundle/main.thor +1 -0
- data/test/fixtures/doc/%file_name%.rb.tt +1 -0
- data/test/fixtures/doc/COMMENTER +10 -0
- data/test/fixtures/doc/README +3 -0
- data/test/fixtures/doc/block_helper.rb +3 -0
- data/test/fixtures/doc/components/.empty_directory +0 -0
- data/test/fixtures/doc/config.rb +1 -0
- data/test/fixtures/doc/config.yaml.tt +1 -0
- data/test/fixtures/group.ing.rb +76 -0
- data/test/fixtures/invok.ing.rb +50 -0
- data/test/fixtures/namespace.ing.rb +52 -0
- data/test/fixtures/require.ing.rb +7 -0
- data/test/fixtures/task.ing.rb +36 -0
- data/test/fixtures/task.thor +10 -0
- data/test/spec_helper.rb +2 -0
- data/test/test_helper.rb +41 -0
- data/todo.yml +7 -0
- metadata +147 -0
data/lib/ing/version.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# patch to access captures in gsub_file
|
2
|
+
# https://github.com/kentaroi/thor/commit/46b6d0b18a58eb8f7586e57eb633e96664fb1722
|
3
|
+
#
|
4
|
+
class Thor
|
5
|
+
module Actions
|
6
|
+
|
7
|
+
def gsub_file(path, flag, *args, &block)
|
8
|
+
return unless behavior == :invoke
|
9
|
+
config = args.last.is_a?(Hash) ? args.pop : {}
|
10
|
+
|
11
|
+
path = File.expand_path(path, destination_root)
|
12
|
+
say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)
|
13
|
+
|
14
|
+
unless options[:pretend]
|
15
|
+
content = File.binread(path)
|
16
|
+
if block
|
17
|
+
if block.arity == 1
|
18
|
+
content.gsub!(flag, *args) { block.call($&) }
|
19
|
+
else
|
20
|
+
content.gsub!(flag, *args) { block.call(*$~) }
|
21
|
+
end
|
22
|
+
else
|
23
|
+
content.gsub!(flag, *args)
|
24
|
+
end
|
25
|
+
File.open(path, 'wb') { |file| file.write(content) }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# monkey patch for better ask behavior
|
2
|
+
|
3
|
+
class Thor
|
4
|
+
module Shell
|
5
|
+
class Basic
|
6
|
+
|
7
|
+
def ask(statement, *args)
|
8
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
9
|
+
color = args.pop
|
10
|
+
default = options[:default]
|
11
|
+
if options[:limited_to]
|
12
|
+
ask_filtered(statement, options[:limited_to], color, default)
|
13
|
+
else
|
14
|
+
ask_simply(statement, color, default)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def yes?(statement, *args)
|
19
|
+
!!(ask(statement, *args) =~ is?(:yes))
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
|
25
|
+
def ask_simply(statement, color=nil, default=nil)
|
26
|
+
say("#{statement} #{default ? '(default ' + default + ')' : nil} ", color)
|
27
|
+
input = stdin.gets.strip
|
28
|
+
input.empty? ? default : input
|
29
|
+
end
|
30
|
+
|
31
|
+
def ask_filtered(statement, answer_set, color=nil, default=nil)
|
32
|
+
correct_answer = nil
|
33
|
+
until correct_answer
|
34
|
+
answer = ask_simply("#{statement} #{answer_set.inspect}", color, default)
|
35
|
+
correct_answer = answer_set.include?(answer) ? answer : nil
|
36
|
+
answers = answer_set.map(&:inspect).join(", ")
|
37
|
+
say("Your response must be one of: [#{answers}]. Please try again.") unless correct_answer
|
38
|
+
end
|
39
|
+
correct_answer
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require File.expand_path('../test_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe Ing do
|
4
|
+
include TestHelpers
|
5
|
+
|
6
|
+
def capture_run(args)
|
7
|
+
capture(:stdout) { Ing.run args }
|
8
|
+
end
|
9
|
+
|
10
|
+
def reset
|
11
|
+
Ing::Dispatcher.dispatched.clear
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#run" do
|
15
|
+
|
16
|
+
describe "no method or args given" do
|
17
|
+
before { reset }
|
18
|
+
subject { ["count_args"] }
|
19
|
+
|
20
|
+
it 'should run with expected output' do
|
21
|
+
assert_equal "CountArgs called with 0 args",
|
22
|
+
capture_run(subject).chomp
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "method given with args" do
|
28
|
+
before { reset }
|
29
|
+
subject { ["amazing", "describe", "Malcolm"] }
|
30
|
+
|
31
|
+
it 'should run with expected output' do
|
32
|
+
assert_equal "Malcolm is amazing", capture_run(subject).chomp
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "option args given" do
|
38
|
+
before { reset }
|
39
|
+
subject { ["amazing", "describe", "--forcefully", "Malcolm"] }
|
40
|
+
|
41
|
+
it 'should run with expected output' do
|
42
|
+
assert_equal "MALCOLM IS AMAZING", capture_run(subject).chomp
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "and option args given at end" do
|
46
|
+
before { reset }
|
47
|
+
subject { ["amazing", "describe", "Malcolm", "--forcefully"] }
|
48
|
+
|
49
|
+
it 'should run with expected output' do
|
50
|
+
assert_equal "MALCOLM IS AMAZING", capture_run(subject).chomp
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "unknown method given" do
|
57
|
+
before { reset }
|
58
|
+
subject { ["amazing", "write", "Malcolm"] }
|
59
|
+
|
60
|
+
it 'should raise error' do
|
61
|
+
assert_raises(::NoMethodError) { capture_run subject }
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "undefined option given" do
|
67
|
+
before { reset }
|
68
|
+
subject { ["amazing", "describe", "Malcolm", "--times=3"] }
|
69
|
+
|
70
|
+
it 'should exit' do
|
71
|
+
assert_raises(::SystemExit) { capture_run(subject) }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "wrong number of args given" do
|
76
|
+
before { reset }
|
77
|
+
subject { ["amazing", "describe"] }
|
78
|
+
|
79
|
+
it 'should raise error' do
|
80
|
+
assert_raises(::ArgumentError) { capture_run subject }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "require boot option given" do
|
85
|
+
before { reset }
|
86
|
+
subject { ["-r", "./test/fixtures/require.ing",
|
87
|
+
"--require", "cgi",
|
88
|
+
"dynamic_require"
|
89
|
+
]
|
90
|
+
}
|
91
|
+
|
92
|
+
it 'should load specified files and libraries' do
|
93
|
+
capture_run subject
|
94
|
+
DynamicRequire; CGI
|
95
|
+
assert true
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "namespace boot option given" do
|
101
|
+
before { reset }
|
102
|
+
subject { ["--require=./test/fixtures/namespace.ing",
|
103
|
+
"-n", "some_base_namespace",
|
104
|
+
"one:two:three:echo", "call", "hello world"
|
105
|
+
]
|
106
|
+
}
|
107
|
+
|
108
|
+
it 'should run with expected output' do
|
109
|
+
assert_equal "hello world", capture_run(subject).chomp
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "and class not within namespace" do
|
113
|
+
before { reset }
|
114
|
+
subject { ["--require=./test/fixtures/namespace.ing",
|
115
|
+
"-n", "some_base_namespace",
|
116
|
+
"echo", "call", "hello world"
|
117
|
+
]
|
118
|
+
}
|
119
|
+
|
120
|
+
it 'should raise error' do
|
121
|
+
assert_raises(::NameError) { capture_run(subject).chomp }
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "dispatch to proc" do
|
129
|
+
before { reset }
|
130
|
+
subject { %w[p 1 2 3] }
|
131
|
+
|
132
|
+
P = lambda {|*args|
|
133
|
+
opts = (Hash === args.last ? args.pop : {})
|
134
|
+
args.reverse.each_with_index {|a,i| puts "#{i}:#{a}"}
|
135
|
+
}
|
136
|
+
|
137
|
+
it 'should run with expected output' do
|
138
|
+
log = capture_run(subject).chomp
|
139
|
+
assert_equal "0:3\n1:2\n2:1", log
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "invoking within tasks" do
|
147
|
+
before { reset }
|
148
|
+
subject { ["invoking:counter", "one"] }
|
149
|
+
|
150
|
+
it 'should run with expected output' do
|
151
|
+
assert_equal "1\n2\n3\n", capture_run(subject)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "executing within tasks" do
|
156
|
+
before { reset }
|
157
|
+
subject { ["executing:counter", "one"] }
|
158
|
+
|
159
|
+
it 'should run with expected output' do
|
160
|
+
assert_equal "1\n2\n3\n3\n", capture_run(subject)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
|
+
require File.expand_path("../../lib/ing/files", File.dirname(__FILE__))
|
3
|
+
|
4
|
+
describe Ing::Files::CreateFile do
|
5
|
+
include SpecHelpers
|
6
|
+
|
7
|
+
def reset
|
8
|
+
ARGV.replace []
|
9
|
+
::FileUtils.rm_rf(destination_root)
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_file(destination=nil, config={}, options={})
|
13
|
+
@base = MyCounter.new(options)
|
14
|
+
@base.destination_root = destination_root
|
15
|
+
@base.call 1,2
|
16
|
+
MyCounter.send(:define_method, :file_name, Proc.new {'rdoc'} )
|
17
|
+
|
18
|
+
@action = Ing::Files::CreateFile.new(@base, destination, "CONFIGURATION",
|
19
|
+
{ :verbose => !@silence }.merge(config))
|
20
|
+
end
|
21
|
+
|
22
|
+
def invoke!
|
23
|
+
capture(:stdout){ @action.invoke! }
|
24
|
+
end
|
25
|
+
|
26
|
+
def revoke!
|
27
|
+
capture(:stdout){ @action.revoke! }
|
28
|
+
end
|
29
|
+
|
30
|
+
def silence!
|
31
|
+
@silence = true
|
32
|
+
end
|
33
|
+
|
34
|
+
# stubs multiple input responses from $stdin.gets
|
35
|
+
# not currently used
|
36
|
+
class StubInput
|
37
|
+
|
38
|
+
def initialize(expected)
|
39
|
+
@s = Array(expected)
|
40
|
+
end
|
41
|
+
|
42
|
+
def gets
|
43
|
+
@s.shift
|
44
|
+
end
|
45
|
+
|
46
|
+
def reply_for(stream=$stdin, &b)
|
47
|
+
stream.stub(:gets, self.method(:gets), &b)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#invoke!" do
|
53
|
+
before { reset }
|
54
|
+
|
55
|
+
it "creates a file" do
|
56
|
+
create_file("doc/config.rb")
|
57
|
+
invoke!
|
58
|
+
assert File.exists?(File.join(destination_root, "doc/config.rb"))
|
59
|
+
end
|
60
|
+
|
61
|
+
it "does not create a file if pretending" do
|
62
|
+
create_file("doc/config.rb", {}, :pretend => true)
|
63
|
+
invoke!
|
64
|
+
refute File.exists?(File.join(destination_root, "doc/config.rb"))
|
65
|
+
end
|
66
|
+
|
67
|
+
it "shows created status to the user" do
|
68
|
+
create_file("doc/config.rb")
|
69
|
+
assert_equal " create doc/config.rb\n", invoke!
|
70
|
+
end
|
71
|
+
|
72
|
+
it "does not show any information if log status is false" do
|
73
|
+
silence!
|
74
|
+
create_file("doc/config.rb")
|
75
|
+
assert_empty invoke!
|
76
|
+
end
|
77
|
+
|
78
|
+
it "returns the given destination" do
|
79
|
+
capture(:stdout) do
|
80
|
+
assert_equal "doc/config.rb", create_file("doc/config.rb").invoke!
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
it "converts encoded instructions" do
|
85
|
+
create_file("doc/%file_name%.rb.tt")
|
86
|
+
invoke!
|
87
|
+
assert File.exists?(File.join(destination_root, "doc/rdoc.rb.tt"))
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "when file exists" do
|
91
|
+
|
92
|
+
describe "and is identical" do
|
93
|
+
before do
|
94
|
+
reset
|
95
|
+
create_file("doc/config.rb")
|
96
|
+
invoke!
|
97
|
+
end
|
98
|
+
|
99
|
+
it "shows identical status" do
|
100
|
+
create_file("doc/config.rb")
|
101
|
+
invoke!
|
102
|
+
assert_equal " identical doc/config.rb\n", invoke!
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "and is not identical" do
|
107
|
+
before do
|
108
|
+
reset
|
109
|
+
create_file("doc/config.rb")
|
110
|
+
invoke!
|
111
|
+
File.open(File.join(destination_root, 'doc/config.rb'), 'w'){ |f| f.write("FOO = 3") }
|
112
|
+
end
|
113
|
+
|
114
|
+
it "shows forced status to the user if force is given" do
|
115
|
+
refute create_file("doc/config.rb", {}, :force => true).identical?
|
116
|
+
assert_equal " force doc/config.rb\n", invoke!
|
117
|
+
end
|
118
|
+
|
119
|
+
it "shows skipped status to the user if skip is given" do
|
120
|
+
refute create_file("doc/config.rb", {}, :skip => true).identical?
|
121
|
+
assert_equal " skip doc/config.rb\n", invoke!
|
122
|
+
end
|
123
|
+
|
124
|
+
it "shows forced status to the user if force is configured" do
|
125
|
+
refute create_file("doc/config.rb", :force => true).identical?
|
126
|
+
assert_equal " force doc/config.rb\n", invoke!
|
127
|
+
end
|
128
|
+
|
129
|
+
it "shows skipped status to the user if skip is configured" do
|
130
|
+
refute create_file("doc/config.rb", :skip => true).identical?
|
131
|
+
assert_equal " skip doc/config.rb\n", invoke!
|
132
|
+
end
|
133
|
+
|
134
|
+
it "shows conflict status to ther user" do
|
135
|
+
refute create_file("doc/config.rb").identical?
|
136
|
+
file = File.join(destination_root, 'doc/config.rb')
|
137
|
+
content = nil
|
138
|
+
$stdin.stub(:gets,'s') do
|
139
|
+
content = invoke!
|
140
|
+
end
|
141
|
+
assert_match(/conflict doc\/config\.rb/, content)
|
142
|
+
assert_match(/Overwrite #{file}\? \(enter "h" for help\) \[Ynaqdh\]/, content)
|
143
|
+
assert_match(/skip doc\/config\.rb/, content)
|
144
|
+
end
|
145
|
+
|
146
|
+
it "creates the file if the file collision menu returns true" do
|
147
|
+
create_file("doc/config.rb")
|
148
|
+
$stdin.stub(:gets,'y') do
|
149
|
+
assert_match(/force doc\/config\.rb/, invoke!)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
it "skips the file if the file collision menu returns false" do
|
154
|
+
create_file("doc/config.rb")
|
155
|
+
$stdin.stub(:gets,'n') do
|
156
|
+
assert_match(/skip doc\/config\.rb/, invoke!)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Not sure how to do the mock method here without more flexible mocks....
|
161
|
+
# it "executes the block given to show file content" do
|
162
|
+
# create_file("doc/config.rb")
|
163
|
+
# $stdin.should_receive(:gets).and_return('d')
|
164
|
+
# $stdin.should_receive(:gets).and_return('n')
|
165
|
+
# @base.shell.should_receive(:system).with(/diff -u/)
|
166
|
+
# invoke!
|
167
|
+
# end
|
168
|
+
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "#revoke!" do
|
174
|
+
before { reset }
|
175
|
+
|
176
|
+
it "removes the destination file" do
|
177
|
+
create_file("doc/config.rb")
|
178
|
+
invoke!
|
179
|
+
revoke!
|
180
|
+
refute File.exists?(@action.destination)
|
181
|
+
end
|
182
|
+
|
183
|
+
it "does not raise an error if the file does not exist" do
|
184
|
+
create_file("doc/config.rb")
|
185
|
+
revoke!
|
186
|
+
refute File.exists?(@action.destination)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
describe "#exists?" do
|
191
|
+
before { reset }
|
192
|
+
it "returns true if the destination file exists" do
|
193
|
+
create_file("doc/config.rb")
|
194
|
+
refute @action.exists?
|
195
|
+
invoke!
|
196
|
+
assert @action.exists?
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe "#identical?" do
|
201
|
+
before { reset }
|
202
|
+
it "returns true if the destination file and is identical" do
|
203
|
+
create_file("doc/config.rb")
|
204
|
+
refute @action.identical?
|
205
|
+
invoke!
|
206
|
+
assert @action.identical?
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|