starter 0.1.1 → 0.1.2
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.
- 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
|
-
|