batcave 0.0.1 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,3 +1,4 @@
1
1
  source :rubygems
2
2
 
3
3
  gem "clamp"
4
+ gem "cabin"
data/README.md CHANGED
@@ -7,10 +7,22 @@ Wikipedia on "Batcave" uses:
7
7
  > ideal to create a stronghold for his war against crime, and has incorporated a
8
8
  > plethora of equipment as well as expanding the cave for specific uses.
9
9
 
10
- As in coding, you start with some minimal tools and gradually find better
11
- tools, better flows, etc.
10
+ Frankly, I write a lot of code in a lot of languages. There's a lot of
11
+ boilerplate, tools, and scripts I copy from project to project. Debugging,
12
+ coding, documentation, tests, etc all are quite similar in goal across projects
13
+ but differ wildly in implementation. I'd like to codify most of this so that,
14
+ when switching between projects, the cost of context switching isn't as painful.
12
15
 
13
- This project is an experiment to try and make batcave construction possible.
16
+ Essentially, I do roughly the same activities regardless of platform or language.
17
+ This project is an experiment in solving the above problem.
18
+
19
+ Ideally it'd be sweet if this project would also manage my workstation as well
20
+ as my projects. Dotfiles, packages, etc. I'm tired of setting this shit up or
21
+ scripting it sideways every few months.
22
+
23
+ This project may end up looking a lot like an IDE plus some config management.
24
+
25
+ ## Example
14
26
 
15
27
  Maybe, for example, I'm writing an HTTP library in Ruby, and I want to:
16
28
 
@@ -18,11 +30,38 @@ Maybe, for example, I'm writing an HTTP library in Ruby, and I want to:
18
30
  * run tests whenever I modify the code.
19
31
  * make sure all methods have docstrings (with YARD)
20
32
  * have some useful debugging tools.
33
+ * generate documentation to publish online
21
34
 
22
- But new projects should be easier:
35
+ But new projects should be easier, too:
23
36
 
24
37
  * create a 'go' project with a layout that works well with 'goinstall'
25
- * create a 'ruby' project with a standard layout, Gemfile, gemspec, etc
26
- * etc.
38
+ * create a 'ruby' project with a standard layout, Gemfile, gemspec, etc. A bin
39
+ file that uses clamp with sample flag code. A namespace file generated for
40
+ me, etc.
41
+ * automatically create basic tests
42
+ * include tools for debugging
27
43
 
28
44
  Release management should be easier, too.
45
+
46
+ ## Idea: boilerplate and project creation
47
+
48
+ * dk add thing
49
+
50
+ a 'thing' is a feature, boilerplate, some debug tool, metrics or testing tool, etc.
51
+
52
+ Example:
53
+
54
+ * dk add --name example go
55
+ * dk add ruby
56
+
57
+ Both of the above will generate boilerplate projects for their respective
58
+ languages. It currently uses git to find the root of your project directory
59
+ and puts files based from that location.
60
+
61
+ Boilerplates should include basic tests, etc.
62
+
63
+ ## Other ideas in command-line form
64
+
65
+ * dk release - run tests, bump version, build package, run tests, tag it, publish
66
+ * dk add travis-ci - add .travis.yml file with language detection
67
+ * dk debug - run an application inside a debugger (gdb for c/c++, ruby's debugger or pry, etc)
data/batcave.gemspec CHANGED
@@ -2,9 +2,9 @@ Gem::Specification.new do |spec|
2
2
  files = %x{git ls-files}.split("\n")
3
3
 
4
4
  spec.name = "batcave"
5
- spec.version = "0.0.1"
5
+ spec.version = "0.0.4"
6
6
  spec.summary = "Experiments in tools, boilerplatery, debugging, etc."
7
- spec.summary = spec.description
7
+ spec.description = spec.summary
8
8
  spec.add_dependency("clamp")
9
9
  spec.files = files
10
10
  spec.bindir = "bin"
@@ -0,0 +1,43 @@
1
+ require "batcave/namespace"
2
+ require "batcave/support/git"
3
+
4
+ class BatCave::Action::Add
5
+ include BatCave::Support::Git
6
+
7
+ private
8
+
9
+ # Add a new thing with some arguments.
10
+ #
11
+ # Arguments for each thing are defined in the 'THING' file for each ... thing.
12
+ def initialize(thing, args)
13
+ @logger = Cabin::Channel.get("batcave")
14
+ @thing = thing
15
+ @args = args
16
+ end # def initialize
17
+
18
+ def find_thing(thing)
19
+ # look for the 'thing/' or if it's a directory try 'thing/self/'
20
+ [ @thing, File.join(@thing, "self") ].each do |thing|
21
+ path = File.join(BatCave::THINGSDIR, thing)
22
+ config = File.join(path, "THING")
23
+ return config if File.exists?(config)
24
+ end
25
+
26
+ puts "Could not find any thing '#{@thing}'"
27
+ return false
28
+ end # def find_thing
29
+
30
+ def execute
31
+ config = find_thing(@thing)
32
+ return 1 if config == false
33
+ dsl = BatCave::DSL.new(config, @thing, @args)
34
+ dsl.execute
35
+
36
+ # TODO(sissel): Record that we've added this thing.
37
+ puts "Adding #{dsl.environment}/#{@thing}"
38
+ store = BatCave::Store.new
39
+ store.store(dsl)
40
+ end # def execute
41
+
42
+ public(:initialize, :execute)
43
+ end # class BatCave::Action::Add
@@ -1,63 +1,24 @@
1
1
  require "clamp"
2
2
  require "batcave/namespace"
3
- require "batcave/support/git"
3
+ require "batcave/action/add"
4
+ require "batcave/dsl"
5
+ require "batcave/store"
4
6
  require "fileutils"
5
7
 
8
+ # TODO(sissel): Need to track what we've added so we can sync later.
9
+
6
10
  class BatCave::Command::Add < Clamp::Command
7
- include BatCave::Support::Git
8
11
 
12
+ # TODO(sissel): Move this to the 'thing' DSL
9
13
  option ["-n", "--name"], "NAME",
10
14
  "the application or library name", :attribute_name => :name
11
15
 
12
16
  parameter "THING",
13
17
  "The thing to add to your batcave", :attribute_name => :thing
14
18
 
15
- def execute
16
- # TODO(sissel): Move this stuff into a proper batcave library
17
-
18
- found = false
19
- # look for the 'thing/' or if it's a directory try 'thing/self/'
20
- [ @thing, File.join(@thing, "self") ].each do |thing|
21
- path = File.join(BatCave::THINGSDIR, thing)
22
- config = File.join(path, "THING")
23
- if File.exists?(config)
24
- found = true
25
- use(path)
26
- break
27
- end
28
- end
19
+ parameter "[THINGARGS] ...", "arguments to pass to the thing", :attribute_name => :args
29
20
 
30
- if !found
31
- puts "Could not find any thing '#{@thing}'"
32
- end
21
+ def execute
22
+ BatCave::Action::Add.new(@thing, @args).execute
33
23
  end # def execute
34
-
35
- def use(dir)
36
- config = File.join(dir, "THING")
37
- paths = Dir.glob(File.join(dir, "**", "*"))
38
-
39
- paths.each do |path|
40
- next if path == config # skip the 'THING' file
41
- localpath = File.join(project_root, path[dir.length + 1 .. -1])
42
-
43
- if localpath.include?("{name}")
44
- if @name.nil?
45
- raise "Path requires '--name' flag to be set: #{localpath.inspect}"
46
- end
47
- localpath.gsub!("{name}", @name)
48
- end
49
-
50
- # Replace '{...}' in localpath
51
-
52
- # TODO(sissel): if this is a directory, create it.
53
- # TODO(sissel): if this a file, copy it.
54
- if File.directory?(path)
55
- FileUtils.mkdir_p(localpath) unless File.directory?(localpath)
56
- else
57
- localdir = File.dirname(localpath)
58
- FileUtils.mkdir_p(localdir) unless File.directory?(localdir)
59
- FileUtils.cp(path, localpath)
60
- end
61
- end
62
- end
63
24
  end
@@ -1,8 +1,16 @@
1
1
  require "clamp"
2
2
  require "batcave/namespace"
3
+ require "batcave/command/add"
3
4
 
4
5
  class BatCave::Command::Update < Clamp::Command
6
+ parameter "ENVIRONMENT", "The environment to update (user, project, etc)",
7
+ :attribute_name => :environment
8
+
5
9
  def execute
6
- p :Updating
10
+ store = BatCave::Store.new
11
+ store.each(@environment) do |thing, settings|
12
+ args = settings["args"]
13
+ BatCave::Action::Add.new(thing, args).execute
14
+ end
7
15
  end
8
16
  end
@@ -0,0 +1,254 @@
1
+ require "batcave/namespace"
2
+ require "batcave/support/envpath"
3
+ require "fileutils" # stdlib
4
+ require "cabin" # gem 'cabin'
5
+ require "erb" # stdlib
6
+
7
+ # TODO(sissel): DSL is a poor name for this class. Fix it later.
8
+ # TODO(sissel): Split the 'THING' processor from the 'Thing' instances
9
+ class BatCave::DSL
10
+ include BatCave::Support::Git
11
+ include BatCave::Support::EnvPath
12
+
13
+ private
14
+
15
+ def initialize(configfile, thing, args)
16
+ @args = args
17
+ @thing = thing
18
+ @configfile = configfile
19
+ @logger = Cabin::Channel.get("batcave")
20
+
21
+ # Default environment is project.
22
+ @environment = :project
23
+ # Update all files by default
24
+ @create_only = []
25
+
26
+ @target ||= path(@environment)
27
+ @sourcedir = File.dirname(@configfile)
28
+ @sync = true
29
+
30
+ # Make this 'thing' argument into a command by
31
+ # dynamically making a new subclass of Clamp::Command
32
+ @command = Class.new(Clamp::Command).new("<internal dsl thing>")
33
+ class << @command
34
+ def execute
35
+ # nothing to do, we just want to parse flags.
36
+ end
37
+ end
38
+ binding.eval(File.read(@configfile), @configfile)
39
+ end # def initialize
40
+
41
+ # Declare options for this thing. This block will be executed
42
+ # in the context of a Clamp::Command, so anything valid in a
43
+ # Clamp::Command definition is valid here. The options will
44
+ # be parsed immediately after this block is evaluated.
45
+ #
46
+ # Example:
47
+ #
48
+ # options do
49
+ # parameter "SOURCE", "The source to use", :attribute_name => :foo
50
+ # end
51
+ def options(&block)
52
+ @command.class.instance_eval(&block)
53
+ @command.run(@args)
54
+
55
+ # Copy related instance variables from the Clamp::Command to this object.
56
+ @command.instance_variables.each do |ivar|
57
+ # Skip ones that are part of the Command normally (not attributes)
58
+ next if [:@invocation_path, :@context, :@remaining_arguments].include?(ivar)
59
+ instance_variable_set(ivar, @command.instance_variable_get(ivar))
60
+ end
61
+ end # def options
62
+
63
+ # Set the source to use for this thing
64
+ def source(upstream)
65
+ root = File.join(ENV["HOME"], ".batcave", "upstream")
66
+ FileUtils.mkdir_p(root)
67
+ Dir.chdir(root) do
68
+ if !File.directory?(@thing)
69
+ cmd = "git clone #{upstream} #{@thing}"
70
+ else
71
+ #cmd = "cd #{@thing}; git fetch origin master; git reset --hard origin/master"
72
+ cmd = "cd #{@thing}; git pull origin master"
73
+ end
74
+
75
+ @logger.info("Running", :command => cmd)
76
+ system(cmd)
77
+ if $?.exitstatus != 0
78
+ # TODO(sissel): Do something better than aborting
79
+ raise "Command exited #{$?.exitstatus}: #{cmd}"
80
+ end
81
+ end
82
+ @sourcedir = File.join(root, @thing)
83
+ end # def source
84
+
85
+ def target(directory)
86
+ @target = directory
87
+ end # def target
88
+
89
+ # Do path expansion.
90
+ #
91
+ # If the path is /foo/bar/{name}
92
+ # and @names is ["one", "two"], then this will:
93
+ #
94
+ # * yield "/foo/bar/one"
95
+ # * yield "/foo/bar/two"
96
+ #
97
+ # A {foo} will check both @foo and @foos
98
+ def expand(paths, &block)
99
+ skip_re = /(^|\/)\.(\.|git|svn)/
100
+ paths.each do |path|
101
+ next if skip_re.match(path)
102
+ # find all {...} in the string
103
+ tokens = path.scan(/{[^}]+}/)
104
+ if tokens.include?("{name}")
105
+ names = []
106
+ names << @name if instance_variable_defined?(:@name)
107
+ names += @names if instance_variable_defined?(:@names)
108
+
109
+ if names.empty?
110
+ message = [
111
+ "No {name} known, can't expand #{path}",
112
+ "maybe add this to your THING file: ",
113
+ "",
114
+ "options do",
115
+ " parameter 'NAME', 'The {name} value', :attribute_name => :name",
116
+ "end"
117
+ ].join("\n")
118
+ raise message
119
+ end
120
+
121
+ names.each do |name|
122
+ yield path, path.gsub("{name}", name)
123
+ end
124
+ else
125
+ yield path, path
126
+ end
127
+ end
128
+ end # def expand
129
+
130
+ def create_only(*paths)
131
+ if paths.first.is_a?(Array)
132
+ paths = paths.first
133
+ end
134
+
135
+ @create_only = paths
136
+ end # def create_only
137
+
138
+ # Sync two paths
139
+ def sync
140
+ if !instance_variable_defined?(:@sourcedir)
141
+ @logger.error("Can't sync, no source defined")
142
+ return
143
+ end
144
+
145
+ paths = Dir.glob(File.join(@sourcedir, "**", "*"), File::FNM_DOTMATCH)
146
+ expand(paths) do |source, target|
147
+ next if source == @configfile # skip the 'THING' file
148
+ originalpath = source[@sourcedir.length + 1 .. -1]
149
+ localpath = File.join(path(@environment), target[@sourcedir.length + 1 .. -1])
150
+
151
+ if localpath =~ /\.erb$/
152
+ localpath = localpath[0...-4]
153
+ use_erb = true
154
+ else
155
+ use_erb = false
156
+ end
157
+
158
+ # TODO(sissel): if this is a directory, create it.
159
+ # TODO(sissel): if this a file, copy it.
160
+ if File.directory?(source)
161
+ FileUtils.mkdir_p(localpath) unless File.directory?(localpath)
162
+ else
163
+ localdir = File.dirname(localpath)
164
+ FileUtils.mkdir_p(localdir) unless File.directory?(localdir)
165
+
166
+ if @create_only.include?(originalpath) and File.exists?(localpath)
167
+ @logger.info("Skipping existing file due to 'create_only': #{localpath}")
168
+ else
169
+ if use_erb
170
+ erb = ERB.new(File.read(source))
171
+ @logger.info("Generating ", :source => source, :target => localpath)
172
+ File.open(localpath, "w+") do |fd|
173
+ # Make all ivars available as names in the templates, so I can just do
174
+ # <%= name %> instead of <%= @name %>
175
+ ivar = IvarBinding.new(self)
176
+ fd.write(erb.result(ivar.binding))
177
+ end
178
+ else
179
+ @logger.info("Copying", :source => source, :target => localpath)
180
+ FileUtils.cp(source, localpath)
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end # def sync
186
+
187
+ # Set the environment this thing is operating in.
188
+ #
189
+ # Valid environments are: :system, :user, :project, :path
190
+ #
191
+ # This helps hint batcave update operations so you can just update your user,
192
+ # project, etc, instead of everything at once.
193
+ def environment(env=nil)
194
+ if !env.nil?
195
+ @environment = env
196
+ end
197
+ return @environment
198
+ end # def environment
199
+
200
+ def thing
201
+ return @thing
202
+ end # def thing
203
+
204
+ def to_hash
205
+ return {
206
+ "args" => @args
207
+ }
208
+ end # def to_yaml
209
+
210
+ def execute
211
+ sync if @sync
212
+ end
213
+
214
+ def nosync
215
+ @sync = false
216
+ end # def nosync
217
+
218
+ # Metaprogramming to provide instance variables from a class as
219
+ # local-variable-like things in a binding. For use with ERB and such.
220
+ #
221
+ # This is a fun hack.
222
+ class IvarBinding
223
+ def initialize(object)
224
+ # Make a new Object subclass
225
+ klass = Class.new(Object)
226
+
227
+ # Find all instance variables in 'object' and make
228
+ # them methods in our new class. Each method will
229
+ # simply return that named instance variable.
230
+ object.instance_variables.each do |ivar|
231
+ meth = ivar.to_s.gsub("@", "")
232
+ klass.instance_eval do
233
+ define_method(meth) do
234
+ object.instance_variable_get(ivar)
235
+ end
236
+ end
237
+ end
238
+
239
+ # Make a method that returns the binding for this class
240
+ klass.instance_eval do
241
+ define_method(:_binding) do
242
+ return binding
243
+ end
244
+ end
245
+ @instance = klass.new
246
+ end # def initialize
247
+
248
+ def binding
249
+ return @instance._binding
250
+ end # def binding
251
+ end # class IvarBinding
252
+
253
+ public(:initialize, :execute, :environment, :thing, :to_hash)
254
+ end # class BatCave::DSL
data/lib/batcave/main.rb CHANGED
@@ -2,8 +2,19 @@ require "clamp"
2
2
  require "batcave/namespace"
3
3
  require "batcave/command/add"
4
4
  require "batcave/command/update"
5
+ require "cabin"
5
6
 
6
7
  class BatCave::Main < Clamp::Command
8
+ option ["-v", "--verbose"], :flag, "enable verbose logging" do
9
+ require "logger"
10
+ logger = Cabin::Channel.get("batcave")
11
+ p Cabin::Channel.get("batcave").object_id
12
+ p Cabin::Channel.get("batcave").object_id
13
+ p Cabin::Channel.get("batcave").object_id
14
+ logger.subscribe(Logger.new(STDOUT))
15
+ logger.level = :info
16
+ end
17
+
7
18
  # Add something to your bat cave.
8
19
  subcommand "add", "Add something to your batcave", BatCave::Command::Add
9
20
 
@@ -1,5 +1,6 @@
1
1
  module BatCave
2
2
  module Command; end
3
+ module Action; end
3
4
  module Support; end # TODO(sissel): Support is a shitty namespace name.
4
5
  THINGSDIR = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "things"))
5
6
  end
@@ -0,0 +1,74 @@
1
+ require "batcave/namespace"
2
+ require "batcave/support/git"
3
+ require "batcave/support/envpath"
4
+ require "yaml"
5
+ require "fileutils"
6
+
7
+ class BatCave::Store
8
+ include BatCave::Support::Git
9
+ include BatCave::Support::EnvPath
10
+
11
+ def lock(path, &block)
12
+ lockfile = "#{path}.lock"
13
+ File.open(lockfile, "a+") do |lockfd|
14
+ locked = lockfd.flock(File::LOCK_EX | File::LOCK_NB)
15
+ if !locked
16
+ info = lockfd.read
17
+ raise "Store is currently locked, cannot write to it. (info: #{info})"
18
+ end
19
+ lockfd.rewind
20
+ lockfd.write("pid:$$")
21
+ lockfd.flush
22
+
23
+ block.call
24
+ end
25
+
26
+ # This step is not required for flock(2) to work, but it should help to
27
+ # keep users from being confused.
28
+ File.delete(lockfile)
29
+ end # def lock
30
+
31
+ def store(dsl)
32
+ basedir = path(dsl.environment)
33
+ manifest_path = File.join(basedir, ".batcave", "manifest")
34
+ FileUtils.mkdir_p(File.join(basedir, ".batcave"))
35
+
36
+ lock(manifest_path) do
37
+ manifest = load(manifest_path)
38
+ # Store this thing.
39
+ manifest["things"][dsl.thing] = dsl.to_hash
40
+
41
+ # Write the manifest to a tmpfile and rename it.
42
+ tmpfile = manifest_path + ".tmp"
43
+ File.open(tmpfile, "w") do |tmp|
44
+ tmp.write(manifest.to_yaml)
45
+ tmp.flush
46
+ end
47
+ File.rename(tmpfile, manifest_path)
48
+ end
49
+ end # def store
50
+
51
+ def each(environment, &block)
52
+ basedir = path(environment)
53
+ manifest_path = File.join(basedir, ".batcave", "manifest")
54
+ manifest = load(manifest_path)
55
+ manifest["things"].each do |thing|
56
+ yield thing
57
+ end
58
+ end # def each
59
+
60
+ def load(manifest_path)
61
+ manifest = {}
62
+ if File.exists?(manifest_path)
63
+ fd = File.new(manifest_path, "a+")
64
+ # Load the current manifest so we can modify it
65
+ manifest = YAML.load(fd.read)
66
+ manifest = {} if !manifest
67
+ fd.close
68
+ end
69
+
70
+ # Handle empty manifest. (YAML.load returns false for empty files)
71
+ manifest["things"] ||= {}
72
+ return manifest
73
+ end # def manifest
74
+ end # class BatCave::Store
@@ -0,0 +1,14 @@
1
+ require "batcave/namespace"
2
+
3
+ module BatCave::Support::EnvPath
4
+ def path(environment)
5
+ case environment.to_sym
6
+ when :user
7
+ return ENV["HOME"]
8
+ when :project
9
+ return project_root
10
+ else
11
+ raise "Unsupported environment '#{environment}'"
12
+ end
13
+ end # def path
14
+ end
@@ -2,10 +2,12 @@ require "batcave/namespace"
2
2
 
3
3
  module BatCave::Support::Git
4
4
  def project_root
5
+ return @project_root if instance_variable_defined?(:@project_root)
5
6
  root = %x{git rev-parse --show-toplevel}.chomp
6
7
  if $?.exitstatus != 0
7
8
  raise "'git rev-parse --show-toplevel' failed. No project root found. Is this in a git clone?"
8
9
  end
10
+ @project_root = root
9
11
  return root
10
12
  end # def project_root
11
13
  end # class BatCave::Support::Git
@@ -0,0 +1,6 @@
1
+ options do
2
+ parameter "SOURCE", "The source of your dotfiles (git repo, etc?)", :attribute_name => :source
3
+ end
4
+
5
+ environment :user
6
+ source @source
data/things/go/self/THING CHANGED
@@ -0,0 +1,8 @@
1
+ environment :project
2
+
3
+ # Don't overwrite these files on update
4
+ create_only [ "src/{name}/{name}.go" ]
5
+
6
+ options do
7
+ parameter "NAMES ...", "The name of the project", :attribute_name => :names
8
+ end
@@ -1 +1,10 @@
1
+ environment :project
2
+
3
+ # Don't overwrite these files on update
4
+ create_only [ "Gemfile", "{name}.gemspec" ]
5
+
6
+ options do
7
+ parameter "NAME", "The name of the project", :attribute_name => :name
8
+ end
9
+
1
10
  boilerplate = [ "Gemfile" ]
@@ -0,0 +1,20 @@
1
+ Gem::Specification.new do |spec|
2
+ files = %x{git ls-files}
3
+
4
+ spec.name = "<%= name %>"
5
+ spec.version = "0.0.1"
6
+ spec.summary = "<%= name %>"
7
+ spec.description = "<%= name %>"
8
+ spec.license = "none chosen yet"
9
+
10
+ # Note: You should set the version explicitly.
11
+ spec.add_dependency "cabin", ">0" # for logging. apache 2 license
12
+ spec.files = files
13
+ spec.require_paths << "lib"
14
+ spec.bindir = "bin"
15
+
16
+ spec.authors = ["<%= %x{git config --global user.name}.chomp %>"]
17
+ spec.email = ["<%= %x{git config --global user.email}.chomp %>"]
18
+ #spec.homepage = "..."
19
+ end
20
+
@@ -0,0 +1,7 @@
1
+ environment :user
2
+
3
+ options do
4
+ parameter "COMMAND", "The command to run", :attribute_name => :command
5
+ end
6
+
7
+ system(@command)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: batcave
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-14 00:00:00.000000000 Z
12
+ date: 2012-02-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: clamp
16
- requirement: &17501600 !ruby/object:Gem::Requirement
16
+ requirement: &4815200 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,8 +21,8 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *17501600
25
- description:
24
+ version_requirements: *4815200
25
+ description: Experiments in tools, boilerplatery, debugging, etc.
26
26
  email: jls@semicomplete.com
27
27
  executables:
28
28
  - dk
@@ -35,11 +35,16 @@ files:
35
35
  - README.md
36
36
  - batcave.gemspec
37
37
  - bin/dk
38
+ - lib/batcave/action/add.rb
38
39
  - lib/batcave/command/add.rb
39
40
  - lib/batcave/command/update.rb
41
+ - lib/batcave/dsl.rb
40
42
  - lib/batcave/main.rb
41
43
  - lib/batcave/namespace.rb
44
+ - lib/batcave/store.rb
45
+ - lib/batcave/support/envpath.rb
42
46
  - lib/batcave/support/git.rb
47
+ - things/dotfiles/self/THING
43
48
  - things/go/self/THING
44
49
  - things/go/self/src/{name}/{name}.go
45
50
  - things/ruby/self/Gemfile
@@ -47,6 +52,8 @@ files:
47
52
  - things/ruby/self/test/all.rb
48
53
  - things/ruby/self/test/docs.rb
49
54
  - things/ruby/self/test/testing.rb
55
+ - things/ruby/self/{name}.gemspec.erb
56
+ - things/user.sh/THING
50
57
  homepage: https://github.com/jordansissel/batcave
51
58
  licenses: []
52
59
  post_install_message:
@@ -67,9 +74,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
67
74
  version: '0'
68
75
  requirements: []
69
76
  rubyforge_project:
70
- rubygems_version: 1.8.10
77
+ rubygems_version: 1.8.16
71
78
  signing_key:
72
79
  specification_version: 3
73
- summary: ''
80
+ summary: Experiments in tools, boilerplatery, debugging, etc.
74
81
  test_files: []
75
- has_rdoc: