starter 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -0
- data/lib/starter/extensions/module.rb +47 -0
- data/lib/starter/extensions/string.rb +62 -0
- data/lib/starter/http.rb +12 -0
- data/lib/starter/misc.rb +22 -0
- data/lib/starter/mixins/statistics.rb +72 -0
- data/lib/starter/password.rb +28 -0
- data/lib/starter/prompt.rb +24 -0
- data/lib/starter/random.rb +243 -0
- data/lib/starter/tasks/bootstrap.rb +1 -1
- data/lib/starter/tasks/gems.rb +12 -3
- data/lib/starter/tasks/git.rb +1 -1
- data/lib/starter/tasks/github.rb +93 -0
- data/lib/starter/tasks/markdown.rb +1 -1
- data/lib/starter/tasks/npm.rb +29 -2
- data/lib/starter/tasks/{helpers.rb → starter.rb} +9 -16
- metadata +12 -4
- data/lib/starter/string.rb +0 -16
data/Rakefile
CHANGED
@@ -0,0 +1,47 @@
|
|
1
|
+
# "local" methods are those defined directly on a class or module,
|
2
|
+
# as opposed to those inherited or mixed in
|
3
|
+
module Starter
|
4
|
+
module Extensions
|
5
|
+
|
6
|
+
module Module
|
7
|
+
|
8
|
+
def self.basename(mod)
|
9
|
+
mod.name.split('::').last
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.local_methods(mod)
|
13
|
+
mod.public_methods.select do |m|
|
14
|
+
owner = mod.method(m).owner
|
15
|
+
owner == mod.singleton_class || owner == mod
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.local_instance_methods(mod)
|
20
|
+
mod.public_instance_methods.select do |m|
|
21
|
+
owner = mod.instance_method(m).owner
|
22
|
+
owner == mod
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# For every locally-defined class method, create an instance method
|
27
|
+
# of the same name which operates on the instance. This allows you
|
28
|
+
# to create Modules which can be used as mixins, but the methods are
|
29
|
+
# also available on the module itself, in case a user does not want
|
30
|
+
# to include the module.
|
31
|
+
def self.create_instance_methods(mod)
|
32
|
+
self.local_methods(mod).each do |method_name|
|
33
|
+
mod.module_eval <<-METHOD, __FILE__, __LINE__
|
34
|
+
def #{method_name}(*args)
|
35
|
+
#{mod}.#{method_name}(self, *args)
|
36
|
+
end
|
37
|
+
METHOD
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
self.create_instance_methods(self)
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require "starter/extensions/module"
|
2
|
+
module Starter
|
3
|
+
module Extensions
|
4
|
+
|
5
|
+
module String
|
6
|
+
|
7
|
+
def self.camel_case(string)
|
8
|
+
string.split('_').map do |word|
|
9
|
+
"#{word.slice(/^\w/).upcase}#{word.slice(/^\w(\w+)/, 1)}"
|
10
|
+
end.join
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.snake_case(string)
|
14
|
+
string.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.title_case(string)
|
18
|
+
# FIXME: I think that the block form of gsub is not thread safe.
|
19
|
+
string.gsub( /\b\w/ ) { |x| x.upcase }
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.hex(string)
|
23
|
+
string.unpack("H*")[0]
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.unhex(string)
|
27
|
+
[string].pack("H*")
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.xor(str1, str2)
|
31
|
+
a1 = str1.unpack('C*')
|
32
|
+
a2 = str2.unpack('C*') * (str1.length / str2.length + 1)
|
33
|
+
xor = ""
|
34
|
+
0.upto(a1.length - 1) do |i|
|
35
|
+
x = a1[i] ^ a2[i].to_i
|
36
|
+
xor << x.chr()
|
37
|
+
end
|
38
|
+
xor
|
39
|
+
end
|
40
|
+
|
41
|
+
Starter::Extensions::Module.create_instance_methods(self)
|
42
|
+
|
43
|
+
module Compression
|
44
|
+
def self.included(mod)
|
45
|
+
require "zlib"
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.gzip(string)
|
49
|
+
sio = StringIO.new
|
50
|
+
gz = Zlib::GzipWriter.new(sio)
|
51
|
+
gz.write(string)
|
52
|
+
gz.close
|
53
|
+
sio.string
|
54
|
+
end
|
55
|
+
|
56
|
+
Starter::Extensions::Module.create_instance_methods(self)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
data/lib/starter/http.rb
ADDED
data/lib/starter/misc.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
module Starter
|
3
|
+
module Misc
|
4
|
+
|
5
|
+
def marshalize(filename, &block)
|
6
|
+
if File.exist?(filename)
|
7
|
+
File.open(filename) { |f| Marshal.load(f) }
|
8
|
+
elsif File.exist?(filename + ".gz")
|
9
|
+
system "gunzip #{filename}.gz"
|
10
|
+
File.open(filename) { |f| Marshal.load(f) }
|
11
|
+
else
|
12
|
+
val = yield
|
13
|
+
File.open(filename, "w") do |f|
|
14
|
+
Marshal.dump(val, f)
|
15
|
+
end
|
16
|
+
val
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require "starter/extensions/module"
|
2
|
+
module Starter
|
3
|
+
module Mixins
|
4
|
+
|
5
|
+
module Stats
|
6
|
+
|
7
|
+
def self.summary(items)
|
8
|
+
sorted = items.sort
|
9
|
+
[
|
10
|
+
[:mean, sorted.mean],
|
11
|
+
[:stddev, sorted.standard_deviation],
|
12
|
+
[:min, sorted.first],
|
13
|
+
[:q1, sorted._quartile(1)],
|
14
|
+
[:median, sorted._median],
|
15
|
+
[:q3, sorted._quartile(3)],
|
16
|
+
[:max, sorted.last],
|
17
|
+
[:sample_size, sorted.size]
|
18
|
+
]
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.sum(items)
|
22
|
+
s = 0; items.each { |element| s += element }; s
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.mean(items)
|
26
|
+
items.sum.to_f / items.size
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.variance(items)
|
30
|
+
denom = items.size - 1
|
31
|
+
m = items.mean
|
32
|
+
s = 0
|
33
|
+
items.each { |element| s += (element - m)**2; }
|
34
|
+
s / denom
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.standard_deviation(items)
|
38
|
+
Math.sqrt( items.variance )
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.median(items)
|
42
|
+
self._median(items.sort)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.quartile(items, n)
|
46
|
+
raise ArgumentError unless n > 0 && n < 4
|
47
|
+
self._quartile(items.sort, n)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def self._quartile(sorted, n)
|
53
|
+
s = sorted.size
|
54
|
+
sorted[n * s/4]
|
55
|
+
end
|
56
|
+
|
57
|
+
def self._median(sorted)
|
58
|
+
s = sorted.size
|
59
|
+
i = s % 2
|
60
|
+
case i
|
61
|
+
when 0 then sorted[s/2 - 1, 2].mean
|
62
|
+
when 1 then sorted[s/2].to_f
|
63
|
+
end if sorted.size > 0
|
64
|
+
end
|
65
|
+
|
66
|
+
Starter::Extensions::Module.create_instance_methods(self)
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "starter/prompt"
|
2
|
+
module Starter
|
3
|
+
|
4
|
+
class Password < String
|
5
|
+
extend Prompt
|
6
|
+
|
7
|
+
def self.request(service)
|
8
|
+
begin
|
9
|
+
system "stty -echo"
|
10
|
+
value = prompt "Password for #{service}:"
|
11
|
+
ensure
|
12
|
+
system "stty echo"
|
13
|
+
puts
|
14
|
+
end
|
15
|
+
self.new(value)
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(*args)
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
"#<Starter::Password>"
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Starter
|
2
|
+
|
3
|
+
module Prompt
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def prompt(string)
|
7
|
+
print "#{string} "
|
8
|
+
value = STDIN.gets.chomp
|
9
|
+
if value.size > 1
|
10
|
+
return value
|
11
|
+
else
|
12
|
+
puts "No, I really need a value. Try again."
|
13
|
+
prompt(string)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def confirm(string)
|
18
|
+
print "#{string} [y/N] "
|
19
|
+
true if STDIN.gets.chomp =~ /^y/i
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,243 @@
|
|
1
|
+
require "openssl"
|
2
|
+
module Starter
|
3
|
+
module Random
|
4
|
+
|
5
|
+
def self.nonce(length)
|
6
|
+
OpenSSL::Random.random_bytes(length).unpack("H*").join
|
7
|
+
end
|
8
|
+
|
9
|
+
# Taken from http://redshift.sourceforge.net/sci/
|
10
|
+
# sci-0.2/lib/sci/random.rb
|
11
|
+
# Contact Joel VanderWerf, vjoel@users.sourceforge.net
|
12
|
+
# No license specified in original. Copyright assumed to be Joel VanderWerf.
|
13
|
+
|
14
|
+
# Base class for sequences that sample different kinds of distributions.
|
15
|
+
# The actual PRNG must be plugged in at initialization, or else ruby's
|
16
|
+
# global PRNG is used.
|
17
|
+
class Sequence
|
18
|
+
include Math
|
19
|
+
|
20
|
+
class RubyGlobalGenerator
|
21
|
+
def initialize(seed = nil)
|
22
|
+
srand(seed) if seed
|
23
|
+
end
|
24
|
+
def next
|
25
|
+
rand
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :generator
|
30
|
+
|
31
|
+
# Options are :seed and :generator.
|
32
|
+
#
|
33
|
+
# The :generator must either have a method #next that returns
|
34
|
+
# a float between 0 and 1, or a method #new that returns an instance
|
35
|
+
# that has such a #next method.
|
36
|
+
#
|
37
|
+
# If generator is not given, uses ruby's Kernel#rand (beware global state)
|
38
|
+
# and the :seed option.
|
39
|
+
#
|
40
|
+
def initialize opt = {}
|
41
|
+
gen = opt[:generator] || RubyGlobalGenerator
|
42
|
+
if gen.respond_to?(:new)
|
43
|
+
@generator = gen.new(opt[:seed])
|
44
|
+
else
|
45
|
+
@generator = gen
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.serial_count
|
50
|
+
@count ||= 0
|
51
|
+
@count += 1
|
52
|
+
end
|
53
|
+
|
54
|
+
# A utility method for getting a random seed.
|
55
|
+
def self.random_seed
|
56
|
+
Sequence.random_pool_seed ||
|
57
|
+
((Time.now.to_f * 1_000_000_000).to_i % 1_000_000_000) +
|
58
|
+
Sequence.serial_count + Process.pid
|
59
|
+
end
|
60
|
+
|
61
|
+
@@have_dev_random = true # assume so until evidence to contrary
|
62
|
+
|
63
|
+
def self.random_pool_seed
|
64
|
+
## could also get random data from net
|
65
|
+
if @@have_dev_random
|
66
|
+
@random_pool ||= ""
|
67
|
+
if @random_pool.length < 4
|
68
|
+
File.open('/dev/random') do |dr|
|
69
|
+
if select([dr],nil,nil,0)
|
70
|
+
@random_pool << dr.sysread(100)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
if @random_pool.length >= 4
|
75
|
+
@random_pool.slice!(-4..-1).unpack('L')[0]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
rescue SystemCallError
|
79
|
+
@@have_dev_random = false
|
80
|
+
end
|
81
|
+
|
82
|
+
def next
|
83
|
+
@generator.next
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class ConstantSequence < Sequence
|
88
|
+
attr_reader :mean
|
89
|
+
|
90
|
+
def initialize opt = {}
|
91
|
+
@mean = Float(opt[:mean] || 0)
|
92
|
+
end
|
93
|
+
|
94
|
+
def next
|
95
|
+
@mean
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class UniformSequence < Sequence
|
100
|
+
attr_reader :min, :max
|
101
|
+
|
102
|
+
def initialize opt = {}
|
103
|
+
super
|
104
|
+
@min = Float(opt[:min] || 0)
|
105
|
+
@max = Float(opt[:max] || 1)
|
106
|
+
@delta = @max - @min
|
107
|
+
end
|
108
|
+
|
109
|
+
def next
|
110
|
+
@min + @delta*super
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class ExponentialSequence < Sequence
|
115
|
+
attr_reader :mean
|
116
|
+
|
117
|
+
def initialize opt = {}
|
118
|
+
super
|
119
|
+
@mean = Float(opt[:mean] || 1)
|
120
|
+
end
|
121
|
+
|
122
|
+
def next
|
123
|
+
while (x=super) == 0.0; end
|
124
|
+
return -log(x) * @mean
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class GaussianSequence < Sequence
|
129
|
+
attr_reader :mean, :stdev, :min, :max
|
130
|
+
|
131
|
+
def initialize opt = {}
|
132
|
+
super
|
133
|
+
@mean = Float(opt[:mean] || 0)
|
134
|
+
@stdev = Float(opt[:stdev] || 1)
|
135
|
+
@min = opt[:min]; @min = Float(@min) if @min
|
136
|
+
@max = opt[:max]; @max = Float(@max) if @max
|
137
|
+
@nextnext = nil
|
138
|
+
end
|
139
|
+
|
140
|
+
def next
|
141
|
+
if @nextnext
|
142
|
+
result = @mean + @nextnext*@stdev
|
143
|
+
@nextnext = nil
|
144
|
+
|
145
|
+
else
|
146
|
+
begin
|
147
|
+
v1 = 2 * super - 1
|
148
|
+
v2 = 2 * super - 1
|
149
|
+
rsq = v1*v1 + v2*v2
|
150
|
+
end while rsq >= 1 || rsq == 0
|
151
|
+
|
152
|
+
fac = sqrt(-2*log(rsq) / rsq)
|
153
|
+
@nextnext = v1*fac
|
154
|
+
result = @mean + v2*fac*@stdev
|
155
|
+
end
|
156
|
+
|
157
|
+
if @min and result < @min
|
158
|
+
result = @min
|
159
|
+
elsif @max and result > @max
|
160
|
+
result = @max
|
161
|
+
end
|
162
|
+
|
163
|
+
return result
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# Based on newran02:
|
168
|
+
#
|
169
|
+
# Real VariLogNormal::Next(Real mean, Real sd)
|
170
|
+
# {
|
171
|
+
# // should have special version of log for small sd/mean
|
172
|
+
# Real n_var = log(1 + square(sd / mean));
|
173
|
+
# return mean * exp(N.Next() * sqrt(n_var) - 0.5 * n_var);
|
174
|
+
# }
|
175
|
+
#
|
176
|
+
class LogNormalSequence < Sequence
|
177
|
+
attr_reader :mean, :stdev
|
178
|
+
|
179
|
+
def initialize opt = {}
|
180
|
+
@gaussian_seq = GaussianSequence.new(
|
181
|
+
:mean => 0,
|
182
|
+
:stdev => 1,
|
183
|
+
:seed => opt[:seed],
|
184
|
+
:generator => opt[:generator]
|
185
|
+
)
|
186
|
+
|
187
|
+
super :generator => @gaussian_seq
|
188
|
+
|
189
|
+
@mean = Float(opt[:mean] || 1)
|
190
|
+
@stdev = Float(opt[:stdev] || 1)
|
191
|
+
|
192
|
+
n_var = log(1 + (stdev / mean)**2)
|
193
|
+
@sqrt_n_var = sqrt(n_var)
|
194
|
+
@half_n_var = 0.5 * n_var
|
195
|
+
end
|
196
|
+
|
197
|
+
def next
|
198
|
+
mean * exp(super() * @sqrt_n_var - @half_n_var)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
class DiscreteSequence < Sequence
|
203
|
+
attr_reader :distrib
|
204
|
+
|
205
|
+
def initialize opt = {}
|
206
|
+
super
|
207
|
+
@distrib = opt[:distrib] || { 0 => 1.0 }
|
208
|
+
|
209
|
+
sum = @distrib.inject(0) {|sum, (pt, prob)| sum + prob}
|
210
|
+
sum = sum.to_f # so division is ok
|
211
|
+
|
212
|
+
@distrib.keys.each do |point|
|
213
|
+
@distrib[point] /= sum
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def next
|
218
|
+
loop do
|
219
|
+
r = super
|
220
|
+
@distrib.each do |point, probability|
|
221
|
+
if r < probability
|
222
|
+
return point
|
223
|
+
end
|
224
|
+
r -= probability
|
225
|
+
end
|
226
|
+
# repeat if failed to get a result (due to floating point imprecision)
|
227
|
+
end
|
228
|
+
## this would be faster using an rbtree
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
Constant = ConstantSequence
|
233
|
+
Uniform = UniformSequence
|
234
|
+
Exponential = ExponentialSequence
|
235
|
+
Gaussian = GaussianSequence
|
236
|
+
Normal = NormalSequence = GaussianSequence
|
237
|
+
LogNormal = LogNormalSequence
|
238
|
+
Discrete = DiscreteSequence
|
239
|
+
|
240
|
+
end
|
241
|
+
|
242
|
+
|
243
|
+
end
|
data/lib/starter/tasks/gems.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require "starter/tasks/
|
1
|
+
require "starter/tasks/starter"
|
2
2
|
|
3
3
|
gemspec_path = FileList["*.gemspec"].first || "#{$STARTER[:directory]}.gemspec"
|
4
4
|
project_name = gemspec_path.chomp(".gemspec")
|
@@ -13,14 +13,14 @@ directory "lib"
|
|
13
13
|
file "lib/#{project_name}.rb" do |target|
|
14
14
|
File.open(target.name, "w") do |file|
|
15
15
|
file.puts <<-TXT
|
16
|
-
module #{Starter::String.camel_case(project_name)}
|
16
|
+
module #{Starter::Extensions::String.camel_case(project_name)}
|
17
17
|
|
18
18
|
end
|
19
19
|
TXT
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
file gemspec_path
|
23
|
+
file gemspec_path do |target|
|
24
24
|
File.open(target.name, "w") do |file|
|
25
25
|
file.puts gemspec_template(
|
26
26
|
:author => $STARTER[:author],
|
@@ -51,6 +51,15 @@ task "gem:dependencies" => "gemspec" do
|
|
51
51
|
require "pp"
|
52
52
|
pp gemspec.dependencies.first
|
53
53
|
# install dependencies from gemspec
|
54
|
+
|
55
|
+
#require 'rubygems/dependency_installer'
|
56
|
+
#gems = Gem::SourceIndex.from_installed_gems
|
57
|
+
#installer = Gem::DependencyInstaller.new
|
58
|
+
#spec.dependencies.each do |dep|
|
59
|
+
#if gems.find_name(dep.name, dep.requirement).empty?
|
60
|
+
#installer.install(dep.name, dep.requirement)
|
61
|
+
#end
|
62
|
+
#end
|
54
63
|
end
|
55
64
|
|
56
65
|
task "version" => "read_gemspec" do
|
data/lib/starter/tasks/git.rb
CHANGED
@@ -0,0 +1,93 @@
|
|
1
|
+
require "starter/tasks/starter"
|
2
|
+
|
3
|
+
desc "Create an issue on GitHub"
|
4
|
+
task "github:issue" => "github_repo" do
|
5
|
+
|
6
|
+
repo = $STARTER[:github_repo]
|
7
|
+
options = {}
|
8
|
+
$stdout.print "Title: "; $stdout.flush
|
9
|
+
options[:title] = $stdin.readline.strip
|
10
|
+
$stdout.print "Description: "; $stdout.flush
|
11
|
+
options[:description] = $stdin.readline.strip
|
12
|
+
labels = repo.labels.map { |label| label["name"] }.join(" ")
|
13
|
+
$stdout.print "Labels (separate with spaces: [#{labels}]): "; $stdout.flush
|
14
|
+
options[:labels] = $stdin.readline.strip.split(" ")
|
15
|
+
$stdout.puts "Milestone:"
|
16
|
+
repo.milestones.each do |milestone|
|
17
|
+
$stdout.puts "#{milestone['number']} - #{milestone['title']}"
|
18
|
+
end
|
19
|
+
milestone = $stdin.readline.strip
|
20
|
+
options[:milestone] = milestone unless milestone.empty?
|
21
|
+
|
22
|
+
print "Issue details: "
|
23
|
+
if Starter::Prompt.confirm("Create this issue?")
|
24
|
+
result = repo.issues.create(options)
|
25
|
+
if result["errors"]
|
26
|
+
result["errors"].each do |error|
|
27
|
+
$stderr.puts "#{error['resource']}: #{error['message']}"
|
28
|
+
end
|
29
|
+
else
|
30
|
+
$stdout.puts "Issue ##{result['number']} created."
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
task "github_repo" => %w[ github_settings github_password ] do
|
37
|
+
require 'ghee'
|
38
|
+
|
39
|
+
settings = $STARTER[:settings][:github]
|
40
|
+
user, password, repo = settings.values_at(:user, :password, :repo)
|
41
|
+
ghee = Ghee.basic_auth(user,password)
|
42
|
+
|
43
|
+
repo = ghee.repos(repo[:owner], repo[:name])
|
44
|
+
if repo["message"]
|
45
|
+
puts repo["message"]
|
46
|
+
exit
|
47
|
+
else
|
48
|
+
$STARTER[:github_repo] = repo
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
task "github_password" => "github_settings" do
|
55
|
+
require "starter/password"
|
56
|
+
if $STARTER[:settings][:github][:password] == nil
|
57
|
+
password = Starter::Password.request("GitHub")
|
58
|
+
$STARTER[:settings][:github][:password] = password
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
task "read_settings" do
|
64
|
+
require "yaml"
|
65
|
+
begin
|
66
|
+
$STARTER[:settings] = YAML.load_file("settings.yml")
|
67
|
+
rescue Errno::ENOENT
|
68
|
+
$stderr.puts "You do not appear to have a settings.yml file."
|
69
|
+
if Starter::Prompt.confirm("Create a stubbed settings file?")
|
70
|
+
File.open("settings.yml", "w") do |f|
|
71
|
+
settings = {
|
72
|
+
:github => {
|
73
|
+
:user => "YOURUSERNAME",
|
74
|
+
:repo => {:owner => "OWNERNAME", :name => $STARTER[:directory]}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
YAML.dump(settings, f)
|
78
|
+
puts "Created settings.yml. Now go edit it and add it to .gitignore."
|
79
|
+
end
|
80
|
+
end
|
81
|
+
exit
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
task "github_settings" => "read_settings" do
|
87
|
+
if $STARTER[:settings][:github] == nil
|
88
|
+
$stderr.puts "Looks like your settings.yml file isn't set up with a github stanza."
|
89
|
+
exit
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
|
data/lib/starter/tasks/npm.rb
CHANGED
@@ -3,13 +3,40 @@
|
|
3
3
|
task "bootstrap" => %w[ package.json ]
|
4
4
|
|
5
5
|
file "package.json" => %w[ determine_author ] do |target|
|
6
|
-
string = package_template(options)
|
7
6
|
File.open(target.name, "w") do |file|
|
7
|
+
file.puts package(
|
8
|
+
:project_name => $STARTER[:directory],
|
9
|
+
:author => $STARTER[:author],
|
10
|
+
)
|
8
11
|
end
|
9
12
|
end
|
10
13
|
|
11
|
-
|
14
|
+
|
15
|
+
task "npm:release" => %w[ npm:publish ]
|
16
|
+
|
17
|
+
task "npm:publish" do
|
18
|
+
sh "npm publish"
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
def package(options={})
|
24
|
+
project_name, author = options.values_at(:project_name, :author)
|
12
25
|
package = <<-TXT
|
26
|
+
{
|
27
|
+
"name": "#{project_name}",
|
28
|
+
"description": "A new project, a nascent bundle of win, whose author hasn't described it yet.",
|
29
|
+
"author": "#{author}",
|
30
|
+
"version": "0.1.0",
|
31
|
+
"main": "./lib/#{project_name}.js",
|
32
|
+
"files": [
|
33
|
+
"lib"
|
34
|
+
],
|
35
|
+
"dependencies": {
|
36
|
+
},
|
37
|
+
"devDependencies": {
|
38
|
+
}
|
39
|
+
}
|
13
40
|
TXT
|
14
41
|
end
|
15
42
|
|
@@ -1,13 +1,16 @@
|
|
1
1
|
require "pp"
|
2
|
-
require "starter/
|
2
|
+
require "starter/prompt"
|
3
|
+
require "starter/extensions/string"
|
3
4
|
require "git"
|
4
5
|
|
5
6
|
$STARTER ||= {}
|
6
7
|
|
7
8
|
$STARTER[:directory] = File.basename(Dir.pwd)
|
8
9
|
|
10
|
+
# Interface task declarations
|
11
|
+
|
9
12
|
desc "Bootstrap your project"
|
10
|
-
task "bootstrap"
|
13
|
+
task "bootstrap" => "determine_author"
|
11
14
|
|
12
15
|
desc "Build everything that needs building"
|
13
16
|
task "build"
|
@@ -15,11 +18,12 @@ task "build"
|
|
15
18
|
desc "Release the dogs that shoot bees from their mouths"
|
16
19
|
task "release" => %w[ build ]
|
17
20
|
|
21
|
+
|
18
22
|
task "determine_author" => %w[ read_git_config ] do
|
19
23
|
if author = $STARTER[:git].config["user.name"]
|
20
24
|
$STARTER[:author] = author
|
21
25
|
else
|
22
|
-
$STARTER[:author] = prompt("Project author?")
|
26
|
+
$STARTER[:author] = Starter::Prompt.prompt("Project author?")
|
23
27
|
end
|
24
28
|
end
|
25
29
|
|
@@ -28,10 +32,9 @@ task "read_git_config" do
|
|
28
32
|
$STARTER[:git] = g
|
29
33
|
end
|
30
34
|
|
35
|
+
|
31
36
|
def confirm_command(command)
|
32
|
-
|
33
|
-
case STDIN.gets.chomp
|
34
|
-
when /^y/i
|
37
|
+
if Starter::Prompt.confirm("Issue command '#{command}'?")
|
35
38
|
sh command
|
36
39
|
else
|
37
40
|
puts "Cancelled."
|
@@ -39,14 +42,4 @@ def confirm_command(command)
|
|
39
42
|
end
|
40
43
|
end
|
41
44
|
|
42
|
-
def prompt(string)
|
43
|
-
print "#{string} "
|
44
|
-
value = STDIN.gets.chomp
|
45
|
-
if value.size > 1
|
46
|
-
return value
|
47
|
-
else
|
48
|
-
puts "No, I really need a value. Try again."
|
49
|
-
prompt(string)
|
50
|
-
end
|
51
|
-
end
|
52
45
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: starter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-14 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description:
|
15
15
|
email:
|
@@ -20,13 +20,21 @@ files:
|
|
20
20
|
- LICENSE
|
21
21
|
- Rakefile
|
22
22
|
- README.md
|
23
|
-
- lib/starter/
|
23
|
+
- lib/starter/extensions/module.rb
|
24
|
+
- lib/starter/extensions/string.rb
|
25
|
+
- lib/starter/http.rb
|
26
|
+
- lib/starter/misc.rb
|
27
|
+
- lib/starter/mixins/statistics.rb
|
28
|
+
- lib/starter/password.rb
|
29
|
+
- lib/starter/prompt.rb
|
30
|
+
- lib/starter/random.rb
|
24
31
|
- lib/starter/tasks/bootstrap.rb
|
25
32
|
- lib/starter/tasks/gems.rb
|
26
33
|
- lib/starter/tasks/git.rb
|
27
|
-
- lib/starter/tasks/
|
34
|
+
- lib/starter/tasks/github.rb
|
28
35
|
- lib/starter/tasks/markdown.rb
|
29
36
|
- lib/starter/tasks/npm.rb
|
37
|
+
- lib/starter/tasks/starter.rb
|
30
38
|
homepage: https://github.com/automatthew/starter
|
31
39
|
licenses: []
|
32
40
|
post_install_message:
|
data/lib/starter/string.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
|
2
|
-
module Starter
|
3
|
-
module String
|
4
|
-
extend self
|
5
|
-
def camel_case( string )
|
6
|
-
string.split('_').map do |word|
|
7
|
-
"#{word.slice(/^\w/).upcase}#{word.slice(/^\w(\w+)/, 1)}"
|
8
|
-
end.join
|
9
|
-
end
|
10
|
-
|
11
|
-
def snake_case( string )
|
12
|
-
string.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|