quik 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9cfcd6959a822c4714b21cb7e385f9d285b0c836
4
- data.tar.gz: a6b7379512cd27faabfa8eefbc73bedf52387d40
3
+ metadata.gz: 723a9dc766a9d81825110f6f76d6f6ca6f7bcf19
4
+ data.tar.gz: 53bf723602e937cdd75375a61f7cd9b4c84d8908
5
5
  SHA512:
6
- metadata.gz: 583dc0e25b9c7ed40dd5892c2165e94a1c9b7a0d224e31ded7b09832243646306ff28657a010a40ff80fa746493a618d992b873b7a20a545e55472e6b91c0be0
7
- data.tar.gz: 44f335c50fe615d16e6e33a5dab497695c0a69483ed66a522fccbad02e9af28369546e8f8b6bd54720fcb678d0a4f6f5f27d96b339c23a1e4c08bdc4f8a3bebd
6
+ metadata.gz: 288e9e98f8f687353ff4d4df11ad3f7227f509fda8cd2f3cea91145af38b4c38634c069ddb96271a62d166f6bee27e62022b4753d98d62321a3cd1e89363e223
7
+ data.tar.gz: 97c17d397e54d6eb68d8e348e4cbdd57248f846b4743f8957d8199d0ccf4c54e48f63d237dfda2d708aacbf403c5b79eb881866470cab5cfea1d61f54c938aad
data/.gemtest ADDED
File without changes
data/Manifest.txt CHANGED
@@ -2,5 +2,23 @@ HISTORY.md
2
2
  Manifest.txt
3
3
  README.md
4
4
  Rakefile
5
+ bin/qk
6
+ bin/quik
5
7
  lib/quik.rb
8
+ lib/quik/builder.rb
9
+ lib/quik/cli/main.rb
10
+ lib/quik/cli/opts.rb
11
+ lib/quik/config.rb
12
+ lib/quik/merger.rb
13
+ lib/quik/package.rb
6
14
  lib/quik/version.rb
15
+ lib/quik/wizard.rb
16
+ test/data/gem-starter-template/Manifest.txt
17
+ test/data/gem-starter-template/README.md
18
+ test/data/gem-starter-template/lib/$filename$.rb
19
+ test/data/gem-starter-template/lib/__filename__/$filename$.rb
20
+ test/data/gem-starter-template/lib/__filename__/__filename__/test.rb
21
+ test/data/gem-starter-template/lib/__filename__/version.rb
22
+ test/helper.rb
23
+ test/test_merger.rb
24
+ test/test_package.rb
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # quik
1
+ # qk/quik - ruby quick starter template script wizard .:. the missing code generator
2
2
 
3
3
  * home :: [github.com/rubylibs/quik](https://github.com/rubylibs/quik)
4
4
  * bugs :: [github.com/rubylibs/quik/issues](https://github.com/rubylibs/quik/issues)
@@ -8,7 +8,84 @@
8
8
 
9
9
  ## Usage
10
10
 
11
- TBD
11
+ The quick gem includes a command line tool that lets you
12
+ run quick starter template scripts. Try:
13
+
14
+ ```
15
+ $ quik --help # or
16
+ $ qk -h
17
+ ```
18
+
19
+ Resulting in:
20
+
21
+ ```
22
+ NAME
23
+ qk/quik - ruby quick starter template script wizard .:. the missing code generator
24
+
25
+ SYNOPSIS
26
+ quik [global options] command [command options] [arguments...]
27
+
28
+ VERSION
29
+ 0.1.0
30
+
31
+ GLOBAL OPTIONS
32
+ --help - Show this message
33
+ --test, --dry_run - (Debug) Dry run; run script in simulation for testing
34
+ --verbose - (Debug) Show debug messages
35
+ --version - Display the program version
36
+
37
+ COMMANDS
38
+ new, n - Run ruby quick starter script
39
+
40
+ help - Shows a list of commands or help for one command
41
+ test - (Debug) Test command suite
42
+ ```
43
+
44
+
45
+ ### Commands
46
+
47
+ [New Wizard](#new-wizard-command---new-n)
48
+
49
+ #### New Wizard Command - `new`, `n`
50
+
51
+ To run a quick starter template wizard script
52
+ to download and install (unzip/unpack) a template archive and configure
53
+ the code ready-to-use. Try:
54
+
55
+
56
+ ```
57
+ $ quik new gem # or
58
+ $ quik n gem # or
59
+ $ qk n gem
60
+ ```
61
+
62
+ This will download the `gem.rb` wizard script
63
+ from the [Rubyref Scripts](https://github.com/rubyref/scripts) repo
64
+ and run through all steps e.g.:
65
+
66
+ ```
67
+ Welcome, to the gem quick starter script.
68
+
69
+ Q: What's your gem's name? [hola]: hello
70
+ Q: What's your gem's module? [Hola]: Hello
71
+
72
+ Thanks! Ready-to-go. Stand back.
73
+
74
+ Downloading Rubyref Gem Starter Template...
75
+ Setting up Rubyref Starter Template...
76
+ ...
77
+ Done.
78
+ ```
79
+
80
+ That's it. Now the gem starter code is ready in the `hello`
81
+ folder.
82
+
83
+
84
+ **More Quick Starter Wizard Scripts**
85
+
86
+ See the [Rubyref Scripts](https://github.com/rubyref/scripts) library.
87
+
88
+
12
89
 
13
90
 
14
91
  ## Install
@@ -23,3 +100,7 @@ Just install the gem:
23
100
  The `quik` scripts are dedicated to the public domain.
24
101
  Use it as you please with no restrictions whatsoever.
25
102
 
103
+ ## Questions? Comments?
104
+
105
+ Send them along to the ruby-talk mailing list.
106
+ Thanks!
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ Hoe.spec 'quik' do
5
5
 
6
6
  self.version = Quik::VERSION
7
7
 
8
- self.summary = 'quik'
8
+ self.summary = 'quik - ruby quick starter template script wizard .:. the missing code generator'
9
9
  self.description = summary
10
10
 
11
11
  self.urls = ['https://github.com/rubylibs/quik']
@@ -19,7 +19,10 @@ Hoe.spec 'quik' do
19
19
 
20
20
  self.extra_deps = [
21
21
  ['logutils'],
22
- ['fetcher']
22
+ ['textutils'],
23
+ ['fetcher'],
24
+ ['rubyzip'],
25
+ ['gli'],
23
26
  ]
24
27
 
25
28
  self.licenses = ['Public Domain']
data/bin/qk ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'quik'
4
+
5
+ Quik.main
data/bin/quik ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'quik'
4
+
5
+ Quik.main
@@ -0,0 +1,94 @@
1
+ #encoding: utf-8
2
+
3
+ module Quik
4
+
5
+ class Builder
6
+
7
+ def self.load_file( path, opts={} )
8
+ code = File.read_utf8( path )
9
+ self.load( code, opts )
10
+ end
11
+
12
+ def self.load( code, opts={} )
13
+ builder = Builder.new( opts )
14
+ builder.instance_eval( code )
15
+ builder
16
+ end
17
+
18
+
19
+ include Wizard ## mixin helpers for say, ask, yes?, no?, select, etc.
20
+
21
+ def initialize( opts={} )
22
+ puts "starting new Quik script #{opts.inspect}; lets go"
23
+
24
+ @test = opts[:dry_run] || opts[:test] || false
25
+ @output_dir = opts[:o] || '.'
26
+ @pak = nil ## for now reference last template pack (in future support many - why?? why not??)
27
+ end
28
+
29
+ ## "global" builder options
30
+ def test?() @test; end ## dry_run option (defaults to false)
31
+ def output_dir() @output_dir; end ## ouptput (root) dir (defaults to . e.g. working folder)
32
+
33
+
34
+
35
+ def use( name, opts={} ) ## short alias for install_template
36
+ install_template( name, opts )
37
+ end
38
+
39
+ def install_template( name, opts= {} )
40
+ puts " handle install_template #{name}, #{opts.inspect}"
41
+
42
+ ## note for now assume name is key
43
+ ## e.g. always downcase (e.g. Gem => gem)
44
+ key = name.downcase
45
+
46
+ if test?
47
+ # do nothing; dry run
48
+ else
49
+ @pak = Package.new( key )
50
+ @pak.download
51
+ ## pak.unzip( "#{@output_dir}/#{key}" )
52
+ end
53
+ end
54
+
55
+
56
+ def config( opts={} )
57
+ puts " handle config block"
58
+ c = OpenConfig.new
59
+ yield( c )
60
+ ## pp c
61
+ h = c.to_h
62
+
63
+ pp h
64
+
65
+ ##
66
+ # check for name
67
+ ## required for output
68
+ ## if no name
69
+ ## use ./ working folder for output!!!
70
+
71
+ name = h['name']
72
+
73
+ if name.nil? || name.empty?
74
+ fail 'sorry; for now name is required for output folder'
75
+ end
76
+
77
+ if test?
78
+ ## do nothing; dry run
79
+ else
80
+ if @pak
81
+ unzip_dir = "./o/#{name}"
82
+ ## step 1: unzip templates
83
+ @pak.unzip( unzip_dir )
84
+ ## step 2: merge templates (using hash/config settings)
85
+ m = Quik::Merger.new
86
+ m.merge( unzip_dir, h )
87
+ end
88
+ end
89
+ end # method config
90
+
91
+
92
+ end # class Builder
93
+
94
+ end # module Quik
@@ -0,0 +1,150 @@
1
+ # encoding: utf-8
2
+
3
+ ### NOTE: wrap gli config into a class
4
+ ## see github.com/davetron5000/gli/issues/153
5
+
6
+ module Quik
7
+
8
+ class Tool
9
+ def initialize
10
+ LogUtils::Logger.root.level = :info # set logging level to info
11
+ end
12
+
13
+ def run( args )
14
+ puts Quik.banner
15
+ Toolii.run( args )
16
+ end
17
+ end
18
+
19
+ ## NOTE: gli added function are class methods (thus, wrap class Toolii in Tool for now)
20
+
21
+ class Toolii
22
+ extend GLI::App
23
+
24
+ def self.logger=(value) @@logger=value; end
25
+ def self.logger() @@logger; end
26
+
27
+ ## todo: find a better name e.g. change to settings? config? safe_opts? why? why not?
28
+ def self.opts=(value) @@opts = value; end
29
+ def self.opts() @@opts; end
30
+
31
+
32
+ logger = LogUtils::Logger.root
33
+ opts = Opts.new
34
+
35
+
36
+ program_desc 'ruby quick starter template script wizard .:. the missing code generator'
37
+ version VERSION
38
+
39
+
40
+ ## desc 'Use only local (offline) cached data; no (online) remote network access'
41
+ ## switch [:l, :local], negatable: false
42
+
43
+ desc '(Debug) Show debug messages'
44
+ switch [:verbose], negatable: false ## todo: use -w for short form? check ruby interpreter if in use too?
45
+
46
+ desc '(Debug) Dry run; run script in simulation for testing'
47
+ switch [:test, :dry_run], negatable: false
48
+
49
+
50
+ def self.fetch_script( name )
51
+
52
+ ## first try local version in working folder
53
+
54
+ text = ''
55
+ local_script = "./#{name}.rb"
56
+ if File.exist?( local_script )
57
+ text = File.read_utf8( local_script )
58
+ else ## fetch remote script
59
+ url = "https://github.com/rubyref/scripts/raw/master/#{name}.rb"
60
+ ## assume utf8 text encoding for now
61
+ worker = Fetcher::Worker.new
62
+ text = worker.read_utf8!( url )
63
+ end
64
+
65
+ text
66
+ end
67
+
68
+
69
+ desc "Run ruby quick starter script"
70
+ arg_name 'NAME' # required theme name
71
+ command [:new,:n] do |c|
72
+
73
+ c.action do |g,o,args|
74
+
75
+ name = args[0] || 'gem'
76
+
77
+ script = fetch_script( name )
78
+ if opts.test?
79
+ puts "dry (test) run:"
80
+ Builder.load( script, test: true )
81
+ else
82
+ Builder.load( script )
83
+ end
84
+
85
+ puts 'Done.'
86
+ end # action
87
+ end # command setup
88
+
89
+
90
+
91
+ desc '(Debug) Test command suite'
92
+ command :test do |c|
93
+ c.action do |g,o,args|
94
+
95
+ puts "hello from test command"
96
+ puts "args (#{args.class.name}):"
97
+ pp args
98
+ puts "o (#{o.class.name}):"
99
+ pp o
100
+ puts "g (#{g.class.name}):"
101
+ pp g
102
+
103
+ LogUtils::Logger.root.debug 'test debug msg'
104
+ LogUtils::Logger.root.info 'test info msg'
105
+ LogUtils::Logger.root.warn 'test warn msg'
106
+
107
+ puts 'Done.'
108
+ end
109
+ end
110
+
111
+
112
+
113
+ pre do |g,c,o,args|
114
+ opts.merge_gli_options!( g )
115
+ opts.merge_gli_options!( o )
116
+
117
+ puts Quik.banner
118
+
119
+ if opts.verbose?
120
+ LogUtils::Logger.root.level = :debug
121
+ end
122
+
123
+ logger.debug "Executing #{c.name}"
124
+ true
125
+ end
126
+
127
+ post do |global,c,o,args|
128
+ logger.debug "Executed #{c.name}"
129
+ true
130
+ end
131
+
132
+
133
+ on_error do |e|
134
+ puts
135
+ puts "*** error: #{e.message}"
136
+
137
+ if opts.verbose?
138
+ puts e.backtrace
139
+ end
140
+
141
+ false # skip default error handling
142
+ end
143
+
144
+
145
+ ### exit run(ARGV) ## note: use Toolii.run( ARGV ) outside of class
146
+
147
+ end # class Toolii
148
+
149
+ end # module Quik
150
+
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ module Quik
4
+
5
+ class Opts
6
+
7
+ def merge_gli_options!( options = {} )
8
+ @test = true if options[:test] == true
9
+ @verbose = true if options[:verbose] == true
10
+ end
11
+
12
+
13
+ def verbose=(boolean) # add: alias for debug ??
14
+ @verbose = boolean
15
+ end
16
+
17
+ def verbose?
18
+ return false if @verbose.nil? # default verbose/debug flag is false
19
+ @verbose == true
20
+ end
21
+
22
+ def test=(boolean)
23
+ @test = boolean
24
+ end
25
+
26
+ def test?
27
+ return false if @test.nil? # default test/dry-run flag is false
28
+ @test == true
29
+ end
30
+
31
+ end # class Opts
32
+
33
+ end # module Quik
@@ -0,0 +1,60 @@
1
+ #encoding: utf-8
2
+
3
+ module Quik
4
+
5
+ ##
6
+ # used for config block
7
+ # lets you access props (even nested) that don't yet exist
8
+ # and all props get stored in a hash
9
+ #
10
+ # e.g
11
+ # c = OpenConfig.new
12
+ # c.title = 'title'
13
+ # c.author.name = 'name'
14
+
15
+ # c.quik.last_updated = Time.now
16
+ # c.quik.title = 'title'
17
+ # c.quik.name = 'name'
18
+ # c.quik.theme = 'theme'
19
+
20
+ class OpenConfig
21
+
22
+ def initialize
23
+ @h = {}
24
+ end
25
+
26
+ def to_h
27
+ h = {}
28
+ @h.each do |k,v|
29
+ if v.is_a? OpenConfig
30
+ h[ k ] = v.to_h
31
+ else
32
+ h[ k ] = v ## just pass along as is
33
+ end
34
+ end
35
+ h
36
+ end
37
+
38
+ def method_missing( m, *args, &block)
39
+ if m.to_s =~ /^(.*)=$/ ## setter
40
+ puts "config lookup (setter) >#{m}< #{m.class.name}, #{args.inspect}"
41
+ key = m[0..-2].to_s ## cut off trailing =
42
+ @h[ key ] = args[0].to_s # note: assume first arg is value for setter
43
+ # note: for now all values are strings (always use to_s)
44
+ else ## assume getter
45
+ ## fix: add check for args?? must be 0 for getters??
46
+ ## use else super to delegate non-getters??
47
+ puts "config lookup (getter) >#{m}< #{m.class.name}"
48
+ key = m.to_s
49
+ value = @h[ key ]
50
+ if value.nil?
51
+ puts " config add (nested) hash"
52
+ value = @h[ key ] = OpenConfig.new
53
+ end
54
+ value
55
+ end
56
+ end # method_missing
57
+
58
+ end # class OpenConfig
59
+
60
+ end # module Quik
@@ -0,0 +1,202 @@
1
+ # encoding: utf-8
2
+
3
+ module Quik
4
+
5
+ class Merger
6
+
7
+
8
+
9
+ def find_files( root_dir )
10
+ tree = []
11
+
12
+ files = Dir.entries( root_dir )
13
+ files = files.sort
14
+ puts "#{root_dir}:"
15
+ pp files
16
+
17
+ files.each do |file|
18
+ if File.directory?( "#{root_dir}/#{file}" )
19
+ ## note: skip directory if it starts with dot e.g. . or .. or .git etc.
20
+ if file.start_with?( '.' )
21
+ puts "skipping directory >#{file}< (#{root_dir})"
22
+ next
23
+ end
24
+ subtree = find_files( "#{root_dir}/#{file}" )
25
+ tree << [ file, subtree ]
26
+ else
27
+ ## just a "regular" file
28
+ tree << file
29
+ end
30
+ end
31
+ tree
32
+ end
33
+
34
+
35
+ def merge_filenames( root_dir, hash, opts={} ) ## flags e.g. noop, verbose, etc. see FileUtils
36
+ tree = find_files( root_dir )
37
+ pp tree
38
+
39
+ flags = { ## always use verbose mode for now
40
+ verbose: true
41
+ }
42
+
43
+ ## todo/check: move opts={} to initialize e.g. Merger.new( opts={}) why? why not??
44
+
45
+ ## check for noop e.g. test mode/dry run
46
+ flags[ :noop ] = true if opts[:test] || opts[:dry_run] || opts[:noop]
47
+
48
+ puts "walk tree:"
49
+ merge_filenames_worker_step1( root_dir, hash, tree, flags )
50
+ merge_filenames_worker_step2( root_dir, hash, tree, flags )
51
+ end
52
+
53
+ def merge_filenames_worker_step1( root_dir, hash, tree, flags )
54
+ ## note: step 1 move all files
55
+ ## step 2 move all dirs
56
+
57
+ tree.each do |node|
58
+ if node.is_a? Array ## assume it's a directory
59
+ merge_filenames_worker_step1( "#{root_dir}/#{node[0]}", hash, node[1], flags )
60
+ else ## assume it's a file
61
+ old_name = node
62
+ new_name = merge_path( old_name, hash )
63
+ if old_name == new_name
64
+ puts " keep file #{node} (#{root_dir})"
65
+ else
66
+ puts " *** move file #{old_name} => #{new_name} (#{root_dir})"
67
+ src_path = "#{root_dir}/#{old_name}"
68
+ dest_path = "#{root_dir}/#{new_name}"
69
+ FileUtils.mv( src_path, dest_path, flags )
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ def merge_filenames_worker_step2( root_dir, hash, tree, flags )
76
+ ## note: step 1 move all files
77
+ ## step 2 move all dirs
78
+
79
+ tree.each do |node|
80
+ if node.is_a? Array ## assume it's a directory
81
+ merge_filenames_worker_step2( "#{root_dir}/#{node[0]}", hash, node[1], flags )
82
+ old_name = node[0]
83
+ new_name = merge_path( old_name, hash )
84
+ if old_name == new_name
85
+ puts " keep dir #{node[0]} (#{root_dir})"
86
+ else
87
+ puts " *** move dir #{old_name} => #{new_name} (#{root_dir})"
88
+ src_path = "#{root_dir}/#{old_name}"
89
+ dest_path = "#{root_dir}/#{new_name}"
90
+ FileUtils.mv( src_path, dest_path, flags )
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+
97
+
98
+ def merge_files( root_dir, hash, opts={} )
99
+ ## note: rescan files (after renames)
100
+ tree = find_files( root_dir )
101
+ pp tree
102
+
103
+ puts "walk tree:"
104
+ merge_files_worker( root_dir, '', hash, tree, opts )
105
+ end
106
+
107
+ def merge_files_worker( root_dir, relative_dir, hash, tree, opts )
108
+ tree.each do |node|
109
+ if node.is_a? Array ## assume it's a directory
110
+ if relative_dir.empty? # e.g. just add w/o leading slash e.g. 'lib' and not '/lib'
111
+ new_relative_dir = node[0].dup # note: create a new string; just in case
112
+ else
113
+ new_relative_dir = "#{relative_dir}/#{node[0]}"
114
+ end
115
+ merge_files_worker( root_dir, new_relative_dir, hash, node[1], opts )
116
+ else ## assume it's a file
117
+ if relative_dir.empty?
118
+ relative_path = node
119
+ else
120
+ relative_path = "#{relative_dir}/#{node}"
121
+ end
122
+
123
+ src_path = "#{root_dir}/#{relative_path}"
124
+
125
+ ## note: for now assume always assume text files/utf8
126
+ ## fix: change to File.read_utf8 ??
127
+ old_text = File.read( src_path )
128
+ new_text = merge_text( old_text, hash )
129
+
130
+ if opts[:o]
131
+ dest_root = opts[:o]
132
+ dest_path = "#{dest_root}/#{relative_path}"
133
+ ## make sure dest_path exists
134
+ dest_dir = File.dirname( dest_path )
135
+ FileUtils.mkdir_p( dest_dir ) unless Dir.exists?( dest_dir )
136
+ else
137
+ dest_root = root_dir
138
+ dest_path = "#{dest_root}/#{relative_path}"
139
+ end
140
+
141
+ if old_text == new_text
142
+ if opts[:o] ## for testing copy file 1:1
143
+ puts " copy file 1:1 #{node} (#{relative_dir}) in (#{dest_root})"
144
+ FileUtils.cp( src_path, dest_path, verbose: true )
145
+ else
146
+ puts " skip file #{node} (#{relative_dir})"
147
+ end
148
+ else
149
+ puts " *** update file #{node} (#{relative_dir}) in (#{dest_root})"
150
+ File.open( dest_path, 'w' ) do |f|
151
+ f.write new_text
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+
159
+
160
+ def merge_path( path, hash )
161
+ ## e.g. allow
162
+ ## __filename__ or
163
+ ## $filename$ for now
164
+ path.gsub( /(__|\$)([a-z]+)\1/i ) do |_|
165
+ key = $2.to_s
166
+ value = hash[ key ]
167
+ puts " [path] replacing #{key} w/ >#{value}< in (#{path})"
168
+ value
169
+ end
170
+ end
171
+
172
+ def merge_text( text, hash )
173
+ ## e.g. allow
174
+ ## $filename$ for now only in text
175
+ ## note: must include leading and trailing word boundry (/B)
176
+ ## e.g. hello$test$ will not match only "free-standing $test
177
+ ## or in quote e.g. "$test$"
178
+ ## e.g. no letters or digits allowed before or after $ to match
179
+
180
+ ## pp text
181
+
182
+ text.gsub( /\B\$([a-z]+)\$\B/i ) do |_|
183
+ key = $1.to_s
184
+ value = hash[ key ]
185
+ puts " [text] replacing #{key} w/ >#{value}<"
186
+ value
187
+ end
188
+ end
189
+
190
+
191
+
192
+ def merge( root_dir, hash, opts={} )
193
+ puts " merge #{root_dir}, #{hash.inspect}"
194
+
195
+ merge_filenames( root_dir, hash, opts )
196
+ merge_files( root_dir, hash, opts )
197
+ end
198
+
199
+ end # class Merger
200
+
201
+ end # module Quik
202
+
@@ -0,0 +1,99 @@
1
+ # encoding: utf-8
2
+
3
+ module Quik
4
+
5
+ class Package
6
+
7
+ def initialize( key ) ## e.g. rubyref/gems
8
+ if key.index( '/' ).nil? ## if just 'gems' etc; assumbe rubyref "standard" github org
9
+ @key = "rubyref/#{key}"
10
+ else
11
+ @key = key # use as is e.g. seattlerb/hoe etc.
12
+ end
13
+ end
14
+
15
+ def remote_zip_url # remote zip url
16
+ "https://github.com/#{@key}/archive/master.zip"
17
+ end
18
+
19
+ def local_zip_name
20
+ ## note: change / to --I-- for "flat" structure (e.g. no dirs)
21
+ @key.sub( '/', '--I--' ) # note: will NOT include/return .zip extension
22
+ end
23
+
24
+ def local_zip_dir
25
+ "." ## use ./tmp or ./dl or ~/.quik/cache - why?? why not??
26
+ end
27
+
28
+ def local_zip_path # local zip path
29
+ "#{local_zip_dir}/#{local_zip_name}.zip"
30
+ end
31
+
32
+
33
+
34
+ def download
35
+ src = remote_zip_url
36
+ dest_zip = local_zip_path
37
+
38
+ ## make sure dest folder exists
39
+ FileUtils.mkdir_p( local_zip_dir ) unless Dir.exists?( local_zip_dir )
40
+ fetch_archive( src, dest_zip )
41
+ end
42
+
43
+ def unzip( unzip_dir )
44
+ src = local_zip_path
45
+ dest_unzip = unzip_dir ## local_unzip_dir
46
+
47
+ ## check if folders exists? if not create folder in path
48
+ FileUtils.mkdir_p( dest_unzip ) unless Dir.exists?( dest_unzip )
49
+ unzip_archive( src, dest_unzip )
50
+ end
51
+
52
+
53
+ def merge( root_dir, hash )
54
+ ## replace/merge variable in files
55
+ Dir.chdir( "#{root_dir}" ) do
56
+ files = Dir[ '**/*' ] ## get all files
57
+ pp files
58
+ end
59
+ end
60
+
61
+
62
+ private
63
+ def fetch_archive( src, dest )
64
+ ## step 1 - fetch archive
65
+ worker = Fetcher::Worker.new
66
+ worker.copy( src, dest )
67
+ ### fix: add src.sha5
68
+ ### inside folder
69
+ ### lets us check if current HEAD version is in place across datafiles etc.
70
+ ## - try HTTP HEAD ?? to check?
71
+ end
72
+
73
+ def unzip_archive( src, dest, opts={} )
74
+ ### todo/fix: rename or remove root folder -- use opts { root: false or something??}
75
+ # e.g
76
+ # !/starter-gh-pages/_layouts/ becomes
77
+ # !/_layouts/ etc.
78
+ Zip::File.open( src ) do |zipfile|
79
+ zipfile.each do |file|
80
+ if file.directory?
81
+ puts " skip directory zip entry - #{file.name}"
82
+ else
83
+ ### fix: only cut-off if master or gh-pages ???
84
+ ## check if others include root folder?
85
+ name = file.name[ file.name.index('/')+1..-1] ## cut-off root/first path entry
86
+ path = File.join( dest, name)
87
+ puts " unzip file zip entry - #{file.name} to #{path}"
88
+ FileUtils.mkdir_p( File.dirname( path) )
89
+ zipfile.extract(file, path) unless File.exist?(path)
90
+ end
91
+ end
92
+ end
93
+ end # method unzip_theme
94
+
95
+
96
+ end # class Package
97
+
98
+ end # module Quik
99
+
data/lib/quik/version.rb CHANGED
@@ -3,8 +3,8 @@
3
3
  module Quik
4
4
 
5
5
  MAJOR = 0 ## todo: namespace inside version or something - why? why not??
6
- MINOR = 0
7
- PATCH = 1
6
+ MINOR = 1
7
+ PATCH = 0
8
8
  VERSION = [MAJOR,MINOR,PATCH].join('.')
9
9
 
10
10
  def self.version
@@ -0,0 +1,88 @@
1
+ # encoding: utf-8
2
+
3
+
4
+ ## note:
5
+ ## use global $QUIK_WIZARD_STDIN
6
+ ## lets you redirect stdin for testing e.g $QUIK_WIZARD_STDIN = StringIO.new( 'test/n' )
7
+ $QUIK_WIZARD_IN = $stdin
8
+
9
+
10
+ module Quik
11
+
12
+ module Wizard ## use a different name e.g. WizardHelpers, FormHelpers, InputHelper, etc - why, why not??
13
+
14
+ def getstr ## use getstr to avoid conflict w/ gets (use better name? read_string, readline (already exists too), etc.?)
15
+ ## note: gets will include trailing newline (user hits return to enter data)
16
+ ## - use strip for now (remove leading and traling whitspaces) - might later just use chomp ? (jsut removes newlines)
17
+ $QUIK_WIZARD_IN.gets.strip
18
+ end
19
+
20
+ def say( text )
21
+ puts text
22
+ end
23
+
24
+
25
+ YES_REGEX = /y|yes|on|t|true/i ## support YAML true values - double check (YAML does NOT support t/f)
26
+ NO_REGEX = /n|no|off|f|false/i
27
+
28
+ def yes?( question ) ## defaults to yes - why, why not??
29
+ ## todo: strip trailing question mark (?) if present (gets auto-included)
30
+ print( "Q: #{question} (y/n)? [y]: " )
31
+ str = getstr
32
+ if str.empty? || str =~ YES_REGEX
33
+ true
34
+ elsif str =~ NO_REGEX
35
+ false
36
+ else ## warn: unknown value??
37
+ true
38
+ end
39
+ end
40
+
41
+ def no?( question ) ## defaults to yes - why, why not??
42
+ ## todo: strip trailing question mark (?) if present (gets auto-included)
43
+ print( "Q: #{question} (y/n)? [n]: " )
44
+ str = getstr
45
+ if str.empty? || str =~ NO_REGEX
46
+ true
47
+ elsif str =~ YES_REGEX
48
+ false
49
+ else ## warn: unknown value??
50
+ true
51
+ end
52
+ end
53
+
54
+
55
+ def ask( question, default=nil )
56
+ ## todo: strip trailing question mark (?) if present (gets auto-included)
57
+ if default
58
+ print( "Q: #{question}? [#{default}]: " )
59
+ else
60
+ print( "Q: #{question}?: " )
61
+ end
62
+
63
+ str = getstr
64
+ if default && str.empty? ## todo: best way to check for empty string?
65
+ str = default
66
+ end
67
+ str
68
+ end
69
+
70
+
71
+ def select( title, options )
72
+ puts( "Q: #{title}: " )
73
+ options.each_with_index do |opt,i|
74
+ puts " #{i+1} - #{opt}"
75
+ end
76
+ print( " Your choice (1-#{options.size})? [1]: " )
77
+ str = getstr
78
+ if str.empty? ## todo: best way to check for empty string?
79
+ num = 0 ## default to first option for now
80
+ else
81
+ num = str.to_i ## note: defaults to 0 if cannot convert?
82
+ num -= 1 if num > 0 ## note: "convert" from 1-based to 0-based for ary; if invalid entry; default to 0
83
+ end
84
+ options[ num ]
85
+ end
86
+
87
+ end # module Wizard
88
+ end # module Quik
data/lib/quik.rb CHANGED
@@ -1,14 +1,43 @@
1
1
  # encoding: utf-8
2
2
 
3
+ # stdlibs
4
+ require 'pp'
5
+ require 'fileutils'
6
+ require 'yaml'
7
+ require 'uri'
3
8
 
9
+ # 3rd party libs/gems
10
+ require 'fetcher'
11
+ require 'textutils' ## used for File.read_utf8
12
+
13
+ ## more 3rd party gems
14
+ require 'zip' # use $ gem install rubyzip
15
+ require 'gli'
4
16
 
5
- # our own code
6
17
 
18
+ # our own code
7
19
  require 'quik/version' # let version always go first
20
+ require 'quik/package'
21
+ require 'quik/merger'
22
+ require 'quik/config'
23
+ require 'quik/wizard'
24
+ require 'quik/builder'
25
+
8
26
 
9
27
 
28
+ require 'quik/cli/opts'
29
+ require 'quik/cli/main'
10
30
 
11
31
 
32
+ module Quik
33
+ def self.main
34
+ exit Tool.new.run( ARGV )
35
+ end
36
+ end # module Quik
37
+
12
38
 
13
39
  ## say hello
14
40
  puts Quik.banner if defined?($RUBYLIBS_DEBUG) && $RUBYLIBS_DEBUG
41
+
42
+
43
+ Quik.main if __FILE__ == $0
@@ -0,0 +1,9 @@
1
+ ---
2
+ # Gem Starter Template
3
+ ---
4
+ Manifest.txt
5
+ HISTORY.md
6
+ README.md
7
+ Rakefile
8
+ lib/{{filename}}.rb
9
+ lib/{{filename}}/version.rb
@@ -0,0 +1,22 @@
1
+ # gem-starter-template
2
+
3
+ gem starter template
4
+
5
+
6
+ ## Settings / Config
7
+
8
+ ~~~
9
+ {{ filename }} used for lib/{{ filename }}.rb
10
+ {{ project }} used for gem name
11
+ {{ klass }} used for class name (use class - why? why not?)
12
+ ~~~
13
+
14
+ filename encode with --filename-- for variables e.g. lib/--filename--.rb -- why? why not?
15
+
16
+
17
+ use three jekyll conventions:
18
+
19
+ - folders w/ underscore get ignored
20
+ - files w/ front matter e.g. ---...--- get (pre)processed
21
+ - files w/o front matter get copied 1:1
22
+
File without changes
@@ -0,0 +1,12 @@
1
+
2
+
3
+ module $klass$
4
+ VERSION = $version$
5
+ VERSION2 = "$version$"
6
+ VERSION3 = '$version$'
7
+ VERSION4 = $test
8
+ VERSION5 = test$test$hello
9
+ VERSION6 = test$test$
10
+ VERSION7 = $$
11
+ VERSION8 = $1$2
12
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ ## minitest setup
4
+
5
+ require 'minitest/autorun'
6
+
7
+
8
+ class EchoIO
9
+ def initialize( buf )
10
+ @io = StringIO.new( buf )
11
+ end
12
+
13
+ def gets
14
+ str = @io.gets
15
+ puts "|>#{str.chomp}<|" ## remove newline (w/ chomp) in debug/echo output
16
+ str
17
+ end
18
+ end
19
+
20
+
21
+ ## our own code
22
+ require 'quik'
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ ###
4
+ # to run use
5
+ # ruby -I ./lib -I ./test test/test_merger.rb
6
+
7
+
8
+ require 'helper'
9
+
10
+
11
+ class TestMerger < MiniTest::Test
12
+
13
+ def test_gem_starter_template
14
+
15
+ config = { 'filename' => 'hola',
16
+ 'version' => '0.0.1',
17
+ 'klass' => 'Hola',
18
+ }
19
+
20
+ m = Quik::Merger.new
21
+
22
+ ## m.merge_filenames( "#{Quik.root}/test/data/gem-starter-template", config, test: true )
23
+ ## m.merge_filenames( "./o/gem", config )
24
+
25
+ ## note: set output path (for testing; not in place)
26
+ ## m.merge_files( "#{Quik.root}/test/data/gem-starter-template", config, test: true, o: "./o/#{Time.now.to_i}" )
27
+
28
+ ## note: set output path (for testing; not in place)
29
+ m.merge( "#{Quik.root}/test/data/gem-starter-template", config, test: true, o: "./o/#{Time.now.to_i}" )
30
+ ## m.merge( "./o/gem", config )
31
+
32
+ assert true ## if we get here; everything is ok
33
+ end
34
+
35
+ end # class TestMerger
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ ###
4
+ # to run use
5
+ # ruby -I ./lib -I ./test test/test_package.rb
6
+
7
+
8
+ require 'helper'
9
+
10
+
11
+ class TestPackage < MiniTest::Test
12
+
13
+ def test_gem_starter_template
14
+
15
+ pak = Quik::Package.new( 'gem-starter-template' )
16
+ pak.download
17
+ pak.unzip( './o/gem' )
18
+
19
+ assert true ## if we get here; everything is ok
20
+ end
21
+
22
+ end # class TestPackage
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quik
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-17 00:00:00.000000000 Z
11
+ date: 2015-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logutils
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: textutils
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: fetcher
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +52,34 @@ dependencies:
38
52
  - - ">="
39
53
  - !ruby/object:Gem::Version
40
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubyzip
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: gli
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
41
83
  - !ruby/object:Gem::Dependency
42
84
  name: rdoc
43
85
  requirement: !ruby/object:Gem::Requirement
@@ -66,21 +108,43 @@ dependencies:
66
108
  - - "~>"
67
109
  - !ruby/object:Gem::Version
68
110
  version: '3.13'
69
- description: quik
111
+ description: quik - ruby quick starter template script wizard .:. the missing code
112
+ generator
70
113
  email: ruby-talk@ruby-lang.org
71
- executables: []
114
+ executables:
115
+ - qk
116
+ - quik
72
117
  extensions: []
73
118
  extra_rdoc_files:
74
119
  - HISTORY.md
75
120
  - Manifest.txt
76
121
  - README.md
77
122
  files:
123
+ - ".gemtest"
78
124
  - HISTORY.md
79
125
  - Manifest.txt
80
126
  - README.md
81
127
  - Rakefile
128
+ - bin/qk
129
+ - bin/quik
82
130
  - lib/quik.rb
131
+ - lib/quik/builder.rb
132
+ - lib/quik/cli/main.rb
133
+ - lib/quik/cli/opts.rb
134
+ - lib/quik/config.rb
135
+ - lib/quik/merger.rb
136
+ - lib/quik/package.rb
83
137
  - lib/quik/version.rb
138
+ - lib/quik/wizard.rb
139
+ - test/data/gem-starter-template/Manifest.txt
140
+ - test/data/gem-starter-template/README.md
141
+ - test/data/gem-starter-template/lib/$filename$.rb
142
+ - test/data/gem-starter-template/lib/__filename__/$filename$.rb
143
+ - test/data/gem-starter-template/lib/__filename__/__filename__/test.rb
144
+ - test/data/gem-starter-template/lib/__filename__/version.rb
145
+ - test/helper.rb
146
+ - test/test_merger.rb
147
+ - test/test_package.rb
84
148
  homepage: https://github.com/rubylibs/quik
85
149
  licenses:
86
150
  - Public Domain
@@ -106,5 +170,7 @@ rubyforge_project:
106
170
  rubygems_version: 2.4.2
107
171
  signing_key:
108
172
  specification_version: 4
109
- summary: quik
110
- test_files: []
173
+ summary: quik - ruby quick starter template script wizard .:. the missing code generator
174
+ test_files:
175
+ - test/test_merger.rb
176
+ - test/test_package.rb