boilerpl8 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +21 -0
- data/README.md +68 -0
- data/Rakefile +120 -0
- data/bin/boilerpl8 +5 -0
- data/boilerpl8.gemspec +28 -0
- data/lib/boilerpl8.rb +366 -0
- data/test/boilerpl8_test.rb +101 -0
- metadata +82 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: fb49c7054f7c6e79c7a1eae55ab92aff27410956
|
4
|
+
data.tar.gz: 1b169216fba70c65332f0162885d6390de34d83f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b34f424994767306c2d8aef57a6d3768b93f8e9568d02a14179053359f83f6ae48f7e66b0b12484bb40deef571462b0c190c919e0987dff5f7671429b6172d10
|
7
|
+
data.tar.gz: 205fdebae935f1f716e85bc12a51e5d65c7210a5f37dedaf90d21929b76009a4ff4f17d2e5e4a725b8f1a62558014fea52ab84bf83a6503da33fe6948abcb639
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2016 kuwata-lab.com
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
============
|
2
|
+
Boilerpl8.rb
|
3
|
+
============
|
4
|
+
|
5
|
+
($Release: 0.1.0 $)
|
6
|
+
|
7
|
+
|
8
|
+
Abount
|
9
|
+
------
|
10
|
+
|
11
|
+
Boilerpl8.rb is a scaffolding tool to download and expand boilerplate files.
|
12
|
+
|
13
|
+
|
14
|
+
Install
|
15
|
+
-------
|
16
|
+
|
17
|
+
```console
|
18
|
+
$ gem install boilerpl8
|
19
|
+
$ boilerpl8 --help
|
20
|
+
```
|
21
|
+
|
22
|
+
|
23
|
+
Examples
|
24
|
+
--------
|
25
|
+
|
26
|
+
For Ruby project:
|
27
|
+
|
28
|
+
```console
|
29
|
+
### download boilerplate files from github.com/kwatch/hello-ruby-boilerpl8
|
30
|
+
$ boilerpl8 github:kwatch/hello-ruby myproj
|
31
|
+
```
|
32
|
+
|
33
|
+
For Keight.rb framework:
|
34
|
+
|
35
|
+
```console
|
36
|
+
### download boilerplate files from github.com/kwatch/keight-ruby-boilerpl8
|
37
|
+
$ boilerpl8 github:kwatch/keight-ruby myapp1
|
38
|
+
```
|
39
|
+
|
40
|
+
For HTML5 web site:
|
41
|
+
|
42
|
+
```console
|
43
|
+
### download boilerplate files from github.com/h5bp/html5-boilerplate
|
44
|
+
### ('-B' option doesn't append '-boilerpl8' to github repo name.)
|
45
|
+
$ boilerpl8 -B github:h5bp/html5-boilerplate website1
|
46
|
+
```
|
47
|
+
|
48
|
+
You can expand local *.zip or *.tar.gz file:
|
49
|
+
|
50
|
+
```console
|
51
|
+
$ url="https://github.com/kwatch/hello-ruby-boilerpl8/archive/v0.2.0.zip"
|
52
|
+
$ wget -O hello-ruby-v0.2.0.zip $url
|
53
|
+
$ ls hello-ruby-v0.2.0.zip
|
54
|
+
hello-ruby-v0.2.0.zip
|
55
|
+
$ boilerpl8 file:hello-ruby-v0.2.0.zip myapp1
|
56
|
+
```
|
57
|
+
|
58
|
+
|
59
|
+
Todo
|
60
|
+
----
|
61
|
+
|
62
|
+
* [_] List github repositories which name ends with `-boilerpl8`.
|
63
|
+
|
64
|
+
|
65
|
+
License
|
66
|
+
-------
|
67
|
+
|
68
|
+
MIT License
|
data/Rakefile
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
PROJECT = "boilerpl8"
|
4
|
+
SPECFILE = PROJECT + ".gemspec"
|
5
|
+
|
6
|
+
|
7
|
+
##
|
8
|
+
## tasks
|
9
|
+
##
|
10
|
+
|
11
|
+
task :default => :howto
|
12
|
+
|
13
|
+
|
14
|
+
desc "show how to release"
|
15
|
+
task :howto do
|
16
|
+
puts <<'END'
|
17
|
+
How to release:
|
18
|
+
|
19
|
+
$ git diff # confirm that no diff
|
20
|
+
$ rake test
|
21
|
+
$ rake prepare release=0.0.0 # update release number
|
22
|
+
$ rake package
|
23
|
+
$ rake release
|
24
|
+
$ git checkout . # reset release number
|
25
|
+
$ git tag ruby-0.0.0
|
26
|
+
$ git push --tags
|
27
|
+
|
28
|
+
END
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
desc "run test scripts"
|
33
|
+
task :test do
|
34
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), "lib")
|
35
|
+
#sh "ruby test/**/*_{test,spec}.rb" # not work
|
36
|
+
pattern = 'test/**/*_{test,spec}.rb'
|
37
|
+
files = Dir.glob(pattern)
|
38
|
+
files = [pattern] if files.empty?
|
39
|
+
puts "ruby #{pattern}"
|
40
|
+
sh "ruby", *files, :verbose=>false
|
41
|
+
end
|
42
|
+
### or
|
43
|
+
#require 'rake/testtask'
|
44
|
+
#Rake::TestTask.new do |test|
|
45
|
+
# #test.libs << 'lib' << 'test'
|
46
|
+
# test.test_files = Dir.glob('test/**/*_{test,spec}.rb')
|
47
|
+
# test.verbose = true
|
48
|
+
#end
|
49
|
+
|
50
|
+
|
51
|
+
desc "update release number"
|
52
|
+
task :prepare do
|
53
|
+
release = release_number_required(:prepare)
|
54
|
+
spec = load_gemspec_file(SPECFILE)
|
55
|
+
edit(spec.files) {|s|
|
56
|
+
s.gsub(/\$(Release):.*?\$/, "$Release\: #{release} $") \
|
57
|
+
.gsub(/\$(Release)$/, release)
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
desc "create gem package"
|
63
|
+
task :package do
|
64
|
+
sh "gem build #{SPECFILE}"
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
desc "upload gem to rubygems.org"
|
69
|
+
task :release => :package do
|
70
|
+
spec = load_gemspec_file(SPECFILE)
|
71
|
+
release = spec.version
|
72
|
+
print "*** Are you sure to upload #{PROJECT}-#{release}.gem? [y/N]: "
|
73
|
+
answer = $stdin.gets().strip()
|
74
|
+
if answer =~ /\A[yY]/
|
75
|
+
#sh "git tag ruby-#{release}"
|
76
|
+
sh "gem push #{PROJECT}-#{release}.gem"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
##
|
82
|
+
## helpers
|
83
|
+
##
|
84
|
+
|
85
|
+
def edit(*filepaths)
|
86
|
+
filepaths.flatten.each do |fpath|
|
87
|
+
next if ! File.file?(fpath)
|
88
|
+
File.open(fpath, 'r+b:utf-8') do |f|
|
89
|
+
s = f.read()
|
90
|
+
new_s = yield s
|
91
|
+
if new_s != s
|
92
|
+
f.rewind()
|
93
|
+
f.truncate(0)
|
94
|
+
f.write(new_s)
|
95
|
+
puts "[Change] #{fpath}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def load_gemspec_file(gemspec_file)
|
102
|
+
require 'rubygems'
|
103
|
+
return Gem::Specification::load(gemspec_file)
|
104
|
+
end
|
105
|
+
|
106
|
+
def release_number_required(task_name)
|
107
|
+
release = ENV['release']
|
108
|
+
unless release
|
109
|
+
$stderr.puts <<"END"
|
110
|
+
##
|
111
|
+
## ERROR: rake #{task_name}: requires 'release=X.X.X' option.
|
112
|
+
## For example:
|
113
|
+
## $ rake #{task_name} release=1.0.0
|
114
|
+
##
|
115
|
+
END
|
116
|
+
errmsg = "rake #{task_name}: requires 'release=X.X.X' option."
|
117
|
+
raise ArgumentError.new(errmsg)
|
118
|
+
end
|
119
|
+
return release
|
120
|
+
end
|
data/bin/boilerpl8
ADDED
data/boilerpl8.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = 'boilerpl8'
|
5
|
+
spec.version = '$Release: 0.1.0 $'.split()[1]
|
6
|
+
spec.author = 'makoto kuwata'
|
7
|
+
spec.email = 'kwa@kuwata-lab.com'
|
8
|
+
spec.platform = Gem::Platform::RUBY
|
9
|
+
spec.homepage = 'https://github.com/kwatch/boilerpl8/tree/ruby'
|
10
|
+
spec.summary = "download and expand boilerplate files"
|
11
|
+
spec.description = <<-'END'
|
12
|
+
Scaffolding tool to download and expand boilerplate files.
|
13
|
+
END
|
14
|
+
spec.license = 'MIT'
|
15
|
+
spec.files = Dir[*%w[
|
16
|
+
README.md MIT-LICENSE Rakefile boilerpl8.gemspec
|
17
|
+
bin/*
|
18
|
+
lib/**/*.rb
|
19
|
+
test/**/*.rb
|
20
|
+
]]
|
21
|
+
spec.executables = ['boilerpl8']
|
22
|
+
spec.bindir = 'bin'
|
23
|
+
spec.require_path = 'lib'
|
24
|
+
spec.test_files = Dir['test/**/*_test.rb']
|
25
|
+
|
26
|
+
spec.add_development_dependency 'minitest' , '~> 0'
|
27
|
+
spec.add_development_dependency 'minitest-ok', '~> 0'
|
28
|
+
end
|
data/lib/boilerpl8.rb
ADDED
@@ -0,0 +1,366 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
###
|
4
|
+
### $Release: 0.1.0 $
|
5
|
+
### $Copyright: copyright(c) 2016 kuwata-lab.com all rights reserved $
|
6
|
+
### $License: MIT License $
|
7
|
+
###
|
8
|
+
|
9
|
+
require 'open-uri'
|
10
|
+
require 'json'
|
11
|
+
require 'fileutils'
|
12
|
+
|
13
|
+
|
14
|
+
module Boilerpl8
|
15
|
+
|
16
|
+
|
17
|
+
RELEASE = '$Release: 0.1.0 $'.split()[1]
|
18
|
+
|
19
|
+
|
20
|
+
module ShellHelper
|
21
|
+
|
22
|
+
def rm_rf(path)
|
23
|
+
puts "$ rm -rf #{path}"
|
24
|
+
FileUtils.rm_rf path
|
25
|
+
end
|
26
|
+
|
27
|
+
def mv(oldpath, newpath)
|
28
|
+
puts "$ mv #{oldpath} #{newpath}"
|
29
|
+
File.rename oldpath, newpath
|
30
|
+
end
|
31
|
+
|
32
|
+
def sys(command)
|
33
|
+
puts "$ #{command}"
|
34
|
+
system command
|
35
|
+
end
|
36
|
+
|
37
|
+
def chdir(dir, &block)
|
38
|
+
puts "$ cd #{dir}"
|
39
|
+
Dir.chdir(dir, &block)
|
40
|
+
puts "$ cd -"
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
INITIALIZER_SCRIPTS = [
|
47
|
+
["__init.rb" , "ruby" ],
|
48
|
+
["__init.py" , "python"],
|
49
|
+
["__init.js" , "node" ],
|
50
|
+
["__init.pl" , "perl" ],
|
51
|
+
["__init.php" , "php" ],
|
52
|
+
["__init.lua" , "lua" ],
|
53
|
+
["__init.exs" , "elixir"],
|
54
|
+
["__init.sh" , "bash" ],
|
55
|
+
]
|
56
|
+
|
57
|
+
|
58
|
+
class Operation
|
59
|
+
include ShellHelper
|
60
|
+
|
61
|
+
def do_everything(boilerplate_name, target_dir, options)
|
62
|
+
url, filename = resolve(boilerplate_name, options)
|
63
|
+
filepath = download(url, filename)
|
64
|
+
basedir = extract(filepath, target_dir)
|
65
|
+
kick_initializer(basedir)
|
66
|
+
end
|
67
|
+
|
68
|
+
protected
|
69
|
+
|
70
|
+
def resolve(arg, options)
|
71
|
+
raise NotImplementedError.new("#{self.class.name}#resolve(): not implemented yet.")
|
72
|
+
end
|
73
|
+
|
74
|
+
def download(url, filename)
|
75
|
+
print "Download from #{url} ..."
|
76
|
+
content = open(url) {|f| f.read }
|
77
|
+
puts " done."
|
78
|
+
File.open(filename, 'wb') {|f| f.write(content) }
|
79
|
+
return filename
|
80
|
+
end
|
81
|
+
|
82
|
+
def extract(filename, basedir)
|
83
|
+
filename =~ /\.(zip|tgz|tar\.(gz|bz2|xz))\z/ or
|
84
|
+
err("#{filename}: expected '*.zip' or '*.tar.gz'")
|
85
|
+
base = File.basename($`)
|
86
|
+
basedir ||= base
|
87
|
+
rm_rf basedir if File.exist?(basedir)
|
88
|
+
#
|
89
|
+
case filename
|
90
|
+
when /\.zip\z/
|
91
|
+
tmpdir = basedir + ".tmp"
|
92
|
+
sys "unzip -q -d #{tmpdir} #{filename}"
|
93
|
+
paths = Dir.glob("#{tmpdir}/*")
|
94
|
+
if paths.length == 1 && File.directory?(paths[0])
|
95
|
+
mv paths[0], basedir
|
96
|
+
rm_rf tmpdir
|
97
|
+
else
|
98
|
+
mv tmpdir, basedir
|
99
|
+
end
|
100
|
+
else
|
101
|
+
sys "tar xf #{filename}"
|
102
|
+
mv base, basedir if base != basedir
|
103
|
+
end
|
104
|
+
#
|
105
|
+
return basedir
|
106
|
+
end
|
107
|
+
|
108
|
+
def kick_initializer(basedir)
|
109
|
+
chdir(basedir) do
|
110
|
+
INITIALIZER_SCRIPTS.each do |script, lang|
|
111
|
+
if File.exist?(script)
|
112
|
+
sys "#{lang} #{script}"
|
113
|
+
break
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def err(msg)
|
120
|
+
raise CommandOptionError.new(msg)
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.err(msg)
|
124
|
+
raise CommandOptionError.new(msg)
|
125
|
+
end
|
126
|
+
|
127
|
+
public
|
128
|
+
|
129
|
+
ALL = []
|
130
|
+
|
131
|
+
def self.inherited(klass)
|
132
|
+
ALL << klass
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.create(boilerplate_name)
|
136
|
+
boilerplate_name =~ /\A(\w+:)/ or
|
137
|
+
err("#{args[0]}: expected 'github:' or 'file:' schema.")
|
138
|
+
schema = $1
|
139
|
+
klass = ALL.find {|cls| cls.const_get(:SCHEMA) == schema } or
|
140
|
+
err("#{args[0]}: unknown schema.")
|
141
|
+
return klass.new()
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
class FileSystemOp < Operation
|
148
|
+
|
149
|
+
SCHEMA = "file:"
|
150
|
+
|
151
|
+
protected
|
152
|
+
|
153
|
+
def resolve(arg, options)
|
154
|
+
arg =~ %r'\Afile:(.+)' or err("#{arg}: unexpected format.")
|
155
|
+
filepath = $1
|
156
|
+
return filepath, File.basename(filepath)
|
157
|
+
end
|
158
|
+
|
159
|
+
def download(filepath, filename)
|
160
|
+
return filepath
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
class GithubOp < Operation
|
167
|
+
|
168
|
+
SCHEMA = "github:"
|
169
|
+
|
170
|
+
protected
|
171
|
+
|
172
|
+
def resolve(arg, options)
|
173
|
+
arg =~ %r'\Agithub:([^/]+)/([^/]+)\z' or err("#{arg}: unexpected format.")
|
174
|
+
user, repo = $1, $2
|
175
|
+
#
|
176
|
+
suffix = options['B'] ? "" : "-boilerpl8"
|
177
|
+
api_url = "https://api.github.com/repos/#{user}/#{repo}#{suffix}/releases"
|
178
|
+
begin
|
179
|
+
json_str = open(api_url) {|f| f.read }
|
180
|
+
rescue OpenURI::HTTPError => ex
|
181
|
+
hint = options['B'] \
|
182
|
+
? "confirm repository name, or try without '-B' option." \
|
183
|
+
: "confirm repository name, or maybe you missed '-B' option."
|
184
|
+
err("#{arg}: repository not found\n (api: GET #{api_url})\n (Hint: #{hint})")
|
185
|
+
end
|
186
|
+
#
|
187
|
+
json_arr = JSON.parse(json_str)
|
188
|
+
dict = json_arr[0]
|
189
|
+
asset = (dict["assets"] || [])[0]
|
190
|
+
if asset
|
191
|
+
zip_url = asset["browser_download_url"]
|
192
|
+
filename = zip_url ? File.basename(zip_url) : nil
|
193
|
+
else
|
194
|
+
zip_url = dict["zipball_url"]
|
195
|
+
filename = "#{repo}_#{dict['tag_name']}.zip"
|
196
|
+
end
|
197
|
+
zip_url or
|
198
|
+
err("ERROR: can't find zip file under github.com/#{user}/#{repo}/releases")
|
199
|
+
return zip_url, filename
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
class MainApp
|
206
|
+
|
207
|
+
COMMAND_OPTIONS = [
|
208
|
+
"-h, --help : help",
|
209
|
+
"-v, --version : version",
|
210
|
+
"-B : not append '-boilerpl8' to github repo name",
|
211
|
+
]
|
212
|
+
|
213
|
+
def self.main
|
214
|
+
begin
|
215
|
+
self.new.run(*ARGV)
|
216
|
+
exit 0
|
217
|
+
rescue CommandOptionError => ex
|
218
|
+
$stderr.puts ex.message
|
219
|
+
exit 1
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def initialize(script_name=nil)
|
224
|
+
@script_name = script_name || File.basename($0)
|
225
|
+
end
|
226
|
+
|
227
|
+
def run(*args)
|
228
|
+
parser = CommandOptionParser.new(COMMAND_OPTIONS)
|
229
|
+
options = parser.parse(args)
|
230
|
+
#
|
231
|
+
if options['help']
|
232
|
+
puts help_message()
|
233
|
+
return 0
|
234
|
+
end
|
235
|
+
#
|
236
|
+
if options['version']
|
237
|
+
puts RELEASE
|
238
|
+
return 0
|
239
|
+
end
|
240
|
+
#
|
241
|
+
! args.empty? or err("#{@script_name}: argument required.")
|
242
|
+
boilerplate_name = args[0] # ex: "github:kwatch/hello-ruby"
|
243
|
+
target_dir = args[1] # ex: "mygem1"
|
244
|
+
op = Operation.create(boilerplate_name)
|
245
|
+
op.do_everything(boilerplate_name, target_dir, options)
|
246
|
+
return 0
|
247
|
+
end
|
248
|
+
|
249
|
+
def help_message
|
250
|
+
script = @script_name
|
251
|
+
buf = <<"END"
|
252
|
+
#{script} -- download boilerplate files
|
253
|
+
|
254
|
+
Usage:
|
255
|
+
#{script} [options] github:<USER>/<REPO> <DIR>
|
256
|
+
#{script} [options] file:<PATH> <DIR>
|
257
|
+
|
258
|
+
Options:
|
259
|
+
END
|
260
|
+
COMMAND_OPTIONS.each {|s| buf << " #{s}\n" }
|
261
|
+
buf << <<"END"
|
262
|
+
|
263
|
+
Examples:
|
264
|
+
|
265
|
+
## download boilerplate files from github
|
266
|
+
$ #{script} github:kwatch/hello-ruby mygem1 # for ruby
|
267
|
+
$ #{script} github:kwatch/hello-python mypkg1 # for python
|
268
|
+
$ #{script} github:kwatch/keight-ruby myapp1 # for keight.rb
|
269
|
+
|
270
|
+
## '-B' option doesn't append '-boilerpl8' to github repo name
|
271
|
+
$ #{script} -B github:h5bp/html5-boilerplate website1 # for html5
|
272
|
+
|
273
|
+
## expand boilerplate files
|
274
|
+
$ #{script} file:./keight-ruby.tar.gz myapp1
|
275
|
+
|
276
|
+
END
|
277
|
+
end
|
278
|
+
|
279
|
+
private
|
280
|
+
|
281
|
+
def err(msg)
|
282
|
+
raise CommandOptionError.new(msg)
|
283
|
+
end
|
284
|
+
|
285
|
+
end
|
286
|
+
|
287
|
+
|
288
|
+
class CommandOptionError < StandardError
|
289
|
+
end
|
290
|
+
|
291
|
+
|
292
|
+
CommandOptionDefinition = Struct.new(:short, :long, :param, :desc)
|
293
|
+
|
294
|
+
|
295
|
+
class CommandOptionParser
|
296
|
+
|
297
|
+
def initialize(optdef_strs)
|
298
|
+
@optdef_strs = optdef_strs
|
299
|
+
@optdefs = []
|
300
|
+
optdef_strs.each do |optdef_str|
|
301
|
+
case optdef_str
|
302
|
+
when /-(\w), --(\w[-\w]*)(?:=(\S+))?\s*:\s*(\S.*)?/ ; t = [$1, $2, $3, $4]
|
303
|
+
when /-(\w)(?:\s+(\S+))?\s*:\s*(\S.*)?/ ; t = [$1, nil, $2, $3]
|
304
|
+
when /--(\w[-\w]*)(?:=(\S+))?\s*:\s*(\S.*)?/ ; t = [nil, $1, $2, $3]
|
305
|
+
else
|
306
|
+
raise "unexpected option definition: #{optdef_str}"
|
307
|
+
end
|
308
|
+
short, long, param, desc = t
|
309
|
+
@optdefs << CommandOptionDefinition.new(short, long, param, desc)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
attr_reader :optdefs
|
314
|
+
|
315
|
+
def parse(args)
|
316
|
+
options = {}
|
317
|
+
while ! args.empty? && args[0].start_with?('-')
|
318
|
+
argstr = args.shift
|
319
|
+
if argstr.start_with?('--')
|
320
|
+
rexp = /\A--([-\w]+)(?:=(.*))?\z/
|
321
|
+
argstr =~ rexp or err("#{argstr}: invalid option format.")
|
322
|
+
name, value = $1, $2
|
323
|
+
optdef = find_by(:long, name) or err("--#{name}: unknown option.")
|
324
|
+
optdef.param.nil? || value or err("#{argstr}: argument required.")
|
325
|
+
optdef.param || value.nil? or err("#{argstr}: unexpected argument.")
|
326
|
+
options[optdef.long] = value || true
|
327
|
+
else
|
328
|
+
n = argstr.length
|
329
|
+
i = 0
|
330
|
+
while (i += 1) < n
|
331
|
+
ch = argstr[i]
|
332
|
+
optdef = find_by(:short, ch) or err("-#{ch}: unknown option.")
|
333
|
+
if optdef.param.nil? # no arguments
|
334
|
+
options[optdef.long || optdef.short] = true
|
335
|
+
else # argument required
|
336
|
+
param = argstr[(i+1)..-1]
|
337
|
+
param = args.shift if param.empty?
|
338
|
+
param or err("-#{ch}: argument required.")
|
339
|
+
options[optdef.long || optdef.short] = param
|
340
|
+
break
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
345
|
+
return options
|
346
|
+
end
|
347
|
+
|
348
|
+
private
|
349
|
+
|
350
|
+
def find_by(key, value)
|
351
|
+
return @optdefs.find {|x| x.__send__(key) == value }
|
352
|
+
end
|
353
|
+
|
354
|
+
def err(msg)
|
355
|
+
raise CommandOptionError.new(msg)
|
356
|
+
end
|
357
|
+
|
358
|
+
end
|
359
|
+
|
360
|
+
|
361
|
+
end
|
362
|
+
|
363
|
+
|
364
|
+
if __FILE__ == $0
|
365
|
+
Boilerpl8::MainApp.main()
|
366
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'minitest/spec'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
require 'minitest/ok'
|
6
|
+
|
7
|
+
require 'fileutils'
|
8
|
+
|
9
|
+
require_relative '../lib/boilerpl8'
|
10
|
+
|
11
|
+
|
12
|
+
describe Boilerpl8::MainApp do
|
13
|
+
|
14
|
+
help_message = <<END
|
15
|
+
#{File.basename(__FILE__)} -- download boilerplate files
|
16
|
+
|
17
|
+
Usage:
|
18
|
+
boilerpl8_test.rb [options] github:<USER>/<REPO> <DIR>
|
19
|
+
boilerpl8_test.rb [options] file:<PATH> <DIR>
|
20
|
+
|
21
|
+
Options:
|
22
|
+
-h, --help : help
|
23
|
+
-v, --version : version
|
24
|
+
-B : not append '-boilerpl8' to github repo name
|
25
|
+
|
26
|
+
Examples:
|
27
|
+
|
28
|
+
## download boilerplate files from github
|
29
|
+
$ boilerpl8_test.rb github:kwatch/hello-ruby mygem1 # for ruby
|
30
|
+
$ boilerpl8_test.rb github:kwatch/hello-python mypkg1 # for python
|
31
|
+
$ boilerpl8_test.rb github:kwatch/keight-ruby myapp1 # for keight.rb
|
32
|
+
|
33
|
+
## '-B' option doesn't append '-boilerpl8' to github repo name
|
34
|
+
$ boilerpl8_test.rb -B github:h5bp/html5-boilerplate website1 # for html5
|
35
|
+
|
36
|
+
## expand boilerplate files
|
37
|
+
$ boilerpl8_test.rb file:./keight-ruby.tar.gz myapp1
|
38
|
+
|
39
|
+
END
|
40
|
+
|
41
|
+
describe '#run()' do
|
42
|
+
|
43
|
+
it "prints help message when '-h' or '--help' specified." do
|
44
|
+
expected = help_message
|
45
|
+
#
|
46
|
+
status = nil
|
47
|
+
pr = proc { status = Boilerpl8::MainApp.new.run("-hv") }
|
48
|
+
ok {pr}.output?(expected)
|
49
|
+
ok {status} == 0
|
50
|
+
#
|
51
|
+
status = nil
|
52
|
+
pr = proc { status = Boilerpl8::MainApp.new.run("--help", "foo", "bar") }
|
53
|
+
ok {pr}.output?(expected)
|
54
|
+
ok {status} == 0
|
55
|
+
end
|
56
|
+
|
57
|
+
it "prints version number when '-v' or '--version' specified." do
|
58
|
+
expected = "#{Boilerpl8::RELEASE}\n"
|
59
|
+
#
|
60
|
+
status = nil
|
61
|
+
pr = proc { status = Boilerpl8::MainApp.new.run("-v") }
|
62
|
+
ok {pr}.output?(expected)
|
63
|
+
ok {status} == 0
|
64
|
+
#
|
65
|
+
status = nil
|
66
|
+
pr = proc { status = Boilerpl8::MainApp.new.run("--version", "foo", "bar") }
|
67
|
+
ok {pr}.output?(expected)
|
68
|
+
ok {status} == 0
|
69
|
+
end
|
70
|
+
|
71
|
+
it "downloads and expand github:kwatch/hello-ruby" do
|
72
|
+
target_dir = "test-app1"
|
73
|
+
begin
|
74
|
+
status = Boilerpl8::MainApp.new.run("github:kwatch/hello-ruby", target_dir)
|
75
|
+
ok {target_dir}.dir_exist?
|
76
|
+
ok {"#{target_dir}/#{target_dir}.gemspec"}.file_exist?
|
77
|
+
ok {"#{target_dir}/hello.gemspec"}.NOT.file_exist?
|
78
|
+
ok {"#{target_dir}/__init.rb"}.NOT.file_exist?
|
79
|
+
ok {status} == 0
|
80
|
+
ensure
|
81
|
+
FileUtils.rm_rf target_dir
|
82
|
+
FileUtils.rm_rf Dir.glob("hello-ruby_*.zip")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
it "downloads and expand with '-B' option" do
|
87
|
+
target_dir = "test-site1"
|
88
|
+
begin
|
89
|
+
status = Boilerpl8::MainApp.new.run("-B", "github:h5bp/html5-boilerplate", target_dir)
|
90
|
+
ok {target_dir}.dir_exist?
|
91
|
+
ok {status} == 0
|
92
|
+
ensure
|
93
|
+
FileUtils.rm_rf target_dir
|
94
|
+
FileUtils.rm_rf Dir.glob("html5-boilerplate_*.zip")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: boilerpl8
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- makoto kuwata
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-09-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest-ok
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: 'Scaffolding tool to download and expand boilerplate files.
|
42
|
+
|
43
|
+
'
|
44
|
+
email: kwa@kuwata-lab.com
|
45
|
+
executables:
|
46
|
+
- boilerpl8
|
47
|
+
extensions: []
|
48
|
+
extra_rdoc_files: []
|
49
|
+
files:
|
50
|
+
- MIT-LICENSE
|
51
|
+
- README.md
|
52
|
+
- Rakefile
|
53
|
+
- bin/boilerpl8
|
54
|
+
- boilerpl8.gemspec
|
55
|
+
- lib/boilerpl8.rb
|
56
|
+
- test/boilerpl8_test.rb
|
57
|
+
homepage: https://github.com/kwatch/boilerpl8/tree/ruby
|
58
|
+
licenses:
|
59
|
+
- MIT
|
60
|
+
metadata: {}
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
requirements: []
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 2.5.1
|
78
|
+
signing_key:
|
79
|
+
specification_version: 4
|
80
|
+
summary: download and expand boilerplate files
|
81
|
+
test_files:
|
82
|
+
- test/boilerpl8_test.rb
|