batcave 0.0.1 → 0.0.4

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/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: