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