quik 0.0.1 → 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 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