boson 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,24 +1,28 @@
1
1
  == Description
2
2
  A command/task framework similar to rake and thor that opens your ruby universe to the commandline
3
3
  and irb. For my libraries that use this, see {irbfiles}[http://github.com/cldwalker/irbfiles].
4
+ Works with Ruby 1.8.6 and 1.9.1.
4
5
 
5
6
  == Features
6
- * Commands are just methods that are extended by the toplevel object, main.
7
- * Commands are accessible from the commandline or irb.
8
- * Command libraries can be written as plain ruby which allows for easy testing and use outside of boson.
9
- * Commands can be full-blown commandline apps thanks to automatic views from hirb and powerful
10
- options similar to thor's.
7
+ * Commands are just methods extended for a given object, the default being the top level object, main.
8
+ * Commands are accessible from the commandline (Boson::BinRunner) or irb (Boson::ConsoleRunner).
9
+ * Command libraries, which are just modules, are written in non-dsl ruby which allows for easy testing
10
+ and use outside of boson (Boson::FileLibrary).
11
+ * Comes with default commands to load, search, list and install commands and libraries (Boson::Commands::Core).
12
+ * Commands can be full-blown commandline apps thanks to powerful options (Boson::OptionParser)
13
+ and hirb's views.
14
+ * Commands can have views toggled without adding view code to your original command (Boson::Scientist).
11
15
  * Command libraries are social as a user can install them from a url and then customize command
12
16
  names and options without changing the original library.
13
- * Namespaces are optional and when used are methods which allows for method_missing magic.
17
+ * Namespaces are optional and when used are methods which allow for method_missing magic.
14
18
 
15
19
  == Irb Example
16
20
 
17
- To use in irb, drop this in your irbrc:
21
+ To use in irb, drop this in your ~/.irbrc:
18
22
  require 'boson'
19
- Boson.start :verbose=>true
23
+ Boson.start
20
24
 
21
- Let's start up irb:
25
+ Having done that, let's start up irb:
22
26
 
23
27
  bash> irb
24
28
  Loaded library core
@@ -124,10 +128,23 @@ Let's start up irb:
124
128
 
125
129
  # Sweet! Now we have a list and description of commands that come with irb.
126
130
 
127
- == Creating commands
128
- TODO: Explain library format
131
+ == Creating Command Libraries
132
+ See Boson::FileLibrary or here[http://tagaholic.me/boson/doc/classes/Boson/FileLibrary.html].
129
133
 
130
134
  == Todo
131
135
  * More docs
132
136
  * More tests
133
- * Add tags to libraries + commands
137
+ * Making commands out of existing gems easier and more powerful
138
+ * Better local repositories, perhaps a BosonFile
139
+ * Consider managing extensions to core and standard libraries
140
+ * Consider dropping alias gem dependency if not using its full potential
141
+
142
+ == Motivation
143
+ My {tagging obsession}[http://github.com/cldwalker/tag-tree] from the ruby console.
144
+
145
+ == Acknowledgements
146
+ Boson stands on the shoulders of these people and their ideas:
147
+ * Yehuda Katz and Daniel Berger for an awesome option parser (Boson::OptionParser)
148
+ * Dave Thomas for scraping a method's comments (Boson::CommentInspector)
149
+ * Mauricio Fernandez for scraping a method's arguments (Boson::ArgumentInspector)
150
+ * Chris Wanstrath for inspiring Boson's libraries with Rip's packages.
data/Rakefile CHANGED
@@ -19,13 +19,13 @@ begin
19
19
  Jeweler::Tasks.new do |s|
20
20
  s.name = "boson"
21
21
  s.description = "A command/task framework similar to rake and thor that opens your ruby universe to the commandline and irb."
22
- s.summary = "Although similar to rake and thor, it's focus is not on per-project tasks. Rather it provides users with the power to turn any ruby method, into a full-fledged commandline tool. Boson achieves this with powerful options (borrowed from thor) and views (thanks to hirb). Some other unique features that differentiate it from rake and thor include being accessible from irb and the commandline, being able to write boson commands in non-dsl ruby and toggling a pretty view of a command's output without additional view code."
22
+ s.summary = "Boson provides users with the power to turn any ruby method into a full-fledged commandline tool. Boson achieves this with powerful options (borrowed from thor) and views (thanks to hirb). Some other unique features that differentiate it from rake and thor include being accessible from irb and the commandline, being able to write boson commands in non-dsl ruby and toggling a pretty view of a command's output without additional view code."
23
23
  s.email = "gabriel.horner@gmail.com"
24
24
  s.homepage = "http://github.com/cldwalker/boson"
25
25
  s.authors = ["Gabriel Horner"]
26
26
  s.has_rdoc = true
27
27
  s.rubyforge_project = 'tagaholic'
28
- s.add_dependency 'hirb', '>= 0.2.6'
28
+ s.add_dependency 'hirb', '>= 0.2.7'
29
29
  s.add_dependency 'alias', '>= 0.2.1'
30
30
  s.extra_rdoc_files = ["README.rdoc", "LICENSE.txt"]
31
31
  s.files = FileList["Rakefile", "VERSION.yml", "README.rdoc", "LICENSE.txt", "{bin,lib,test}/**/*"]
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 0
3
- :minor: 0
4
- :patch: 1
3
+ :minor: 1
4
+ :patch: 0
@@ -1,6 +1,6 @@
1
1
  $:.unshift File.dirname(__FILE__) unless $:.include? File.expand_path(File.dirname(__FILE__))
2
2
  %w{hirb alias}.each {|e| require e }
3
- %w{runner runners/repl_runner repo manager loader inspector library}.each {|e| require "boson/#{e}" }
3
+ %w{runner runners/console_runner repo manager loader inspector library}.each {|e| require "boson/#{e}" }
4
4
  %w{argument method comment}.each {|e| require "boson/inspectors/#{e}_inspector" }
5
5
  # order of library subclasses matters
6
6
  %w{module file gem require}.each {|e| require "boson/libraries/#{e}_library" }
@@ -40,7 +40,7 @@ module Boson
40
40
  end
41
41
  end
42
42
 
43
- # The array of loaded repositories.
43
+ # The array of loaded repositories
44
44
  def repos
45
45
  @repos ||= [repo, local_repo].compact
46
46
  end
@@ -54,8 +54,9 @@ module Boson
54
54
  end
55
55
 
56
56
  # Start Boson by loading repositories and their configured libraries.
57
+ # See ConsoleRunner.start for its options.
57
58
  def start(options={})
58
- ReplRunner.start(options)
59
+ ConsoleRunner.start(options)
59
60
  end
60
61
 
61
62
  # Invoke an action on the main object.
@@ -1,5 +1,5 @@
1
1
  module Boson
2
- # A command maps the functionality of a ruby method with the added benefits of options, render_options, etc.
2
+ # A command starts with the functionality of a ruby method and adds benefits with options, render_options, etc.
3
3
  class Command
4
4
  # Creates a command given its name and a library.
5
5
  def self.create(name, library)
@@ -22,6 +22,16 @@ module Boson
22
22
  attr_accessor *(ATTRIBUTES + [:render_options, :namespace])
23
23
  # A hash of attributes which map to instance variables and values. :name
24
24
  # and :lib are required keys.
25
+ #
26
+ # Attributes that can be configured:
27
+ # * *:description*: Description that shows up in command listings
28
+ # * *:alias*: Alternative name for command
29
+ # * *:options*: Hash of options passed to OptionParser
30
+ # * *:render_options*: Hash of rendering options passed to OptionParser
31
+ # * *:args*: Should only be set if not automatically set. This attribute is only
32
+ # important for commands that have options/render_options. Its value can be an array
33
+ # (as ArgumentInspector.scrape_with_eval produces), a number representing
34
+ # the number of arguments or '*' if the command has a variable number of arguments.
25
35
  def initialize(hash)
26
36
  @name = hash[:name] or raise ArgumentError
27
37
  @lib = hash[:lib] or raise ArgumentError
@@ -6,20 +6,20 @@ module Boson::Commands::Core #:nodoc:
6
6
  commands = {
7
7
  'render'=>{:description=>"Render any object using Hirb"},
8
8
  'menu'=>{:description=>"Provide a menu to multi-select elements from a given array"},
9
- 'usage'=>{:description=>"Print a command's usage", :options=>{:verbose=>:boolean}},
9
+ 'usage'=>{:description=>"Print a command's usage", :options=>{[:verbose, :V]=>:boolean}},
10
10
  'commands'=>{ :description=>"List or search commands",
11
- :options=>{:query_fields=>{:default=>['full_name'], :values=>command_attributes},
11
+ :options=>{:query_fields=>{:default=>['full_name'], :values=>command_attributes, :desc=>"Searchable fields"},
12
12
  :index=>{:type=>:boolean, :desc=>"Searches index"}},
13
13
  :render_options=>{:fields=>{:default=>[:full_name, :lib, :alias, :usage, :description], :values=>command_attributes} }
14
14
  },
15
15
  'libraries'=>{ :description=>"List or search libraries",
16
- :options=>{:query_fields=>{:default=>['name'], :values=>library_attributes},
16
+ :options=>{:query_fields=>{:default=>['name'], :values=>library_attributes, :desc=>"Searchable fields"},
17
17
  :index=>{:type=>:boolean, :desc=>"Searches index"} },
18
18
  :render_options=>{
19
19
  :fields=>{:default=>[:name, :commands, :gems, :library_type], :values=>library_attributes},
20
20
  :filters=>{:default=>{:gems=>[:join, ','],:commands=>:size}} }
21
21
  },
22
- 'load_library'=>{:description=>"Load/reload a library", :options=>{:reload=>:boolean, :verbose=>true}}
22
+ 'load_library'=>{:description=>"Load/reload a library", :options=>{:reload=>:boolean, [:verbose,:V]=>true}}
23
23
  }
24
24
 
25
25
  {:library_file=>File.expand_path(__FILE__), :commands=>commands}
@@ -29,13 +29,13 @@ module Boson::Commands::Core #:nodoc:
29
29
  query_fields = options[:query_fields] || ['full_name']
30
30
  Boson::Index.read if options[:index]
31
31
  commands = options[:index] ? Boson::Index.commands : Boson.commands
32
- query_fields.map {|e| commands.select {|f| f.send(e).to_s =~ /#{query}/i } }.flatten
32
+ query_fields.map {|e| commands.select {|f| f.send(e).to_s =~ /#{query}/i } }.flatten.uniq
33
33
  end
34
34
 
35
35
  def libraries(query='', options={})
36
36
  Boson::Index.read if options[:index]
37
37
  libraries = options[:index] ? Boson::Index.libraries : Boson.libraries
38
- options[:query_fields].map {|e| libraries.select {|f| f.send(e).to_s =~ /#{query}/i } }.flatten
38
+ options[:query_fields].map {|e| libraries.select {|f| f.send(e).to_s =~ /#{query}/i } }.flatten.uniq
39
39
  end
40
40
 
41
41
  def load_library(library, options={})
@@ -2,9 +2,12 @@ module Boson::Commands::WebCore #:nodoc:
2
2
  def self.config
3
3
  descriptions = {
4
4
  :install=>"Installs a library by url. Library should then be loaded with load_library.",
5
- :browser=>"Opens urls in a browser", :get=>"Gets the body of a url" }
5
+ :browser=>"Opens urls in a browser on a Mac", :get=>"Gets the body of a url" }
6
6
  commands = descriptions.inject({}) {|h,(k,v)| h[k.to_s] = {:description=>v}; h}
7
- commands['install'][:options] = {:name=>:string, :force=>:boolean}
7
+ commands['install'][:options] = {:name=>{:type=>:string, :desc=>"Library name to save to"},
8
+ :force=>{:type=>:boolean, :desc=>'Overwrites an existing library'},
9
+ :module_wrap=>{:type=>:boolean, :desc=>"Wraps a module around install using library name"},
10
+ :method_wrap=>{:type=>:boolean, :desc=>"Wraps a method and module around installe library using library name"}}
8
11
  {:library_file=>File.expand_path(__FILE__), :commands=>commands}
9
12
  end
10
13
 
@@ -17,10 +20,20 @@ module Boson::Commands::WebCore #:nodoc:
17
20
 
18
21
  def install(url, options={})
19
22
  options[:name] ||= strip_name_from_url(url)
20
- return puts("Please give a library name with this url.") unless options[:name]
23
+ return puts("Please give a library name for this url.") if options[:name].empty?
21
24
  filename = File.join Boson.repo.commands_dir, "#{options[:name]}.rb"
22
25
  return puts("Library name #{options[:name]} already exists. Try a different name.") if File.exists?(filename) && !options[:force]
23
26
  File.open(filename, 'w') {|f| f.write get(url) }
27
+
28
+ if options[:method_wrap] || options[:module_wrap]
29
+ file_string = File.read(filename)
30
+ file_string = "def #{options[:name]}\n#{file_string}\nend" if options[:method_wrap]
31
+ unless (mod_name = Boson::Util.camelize(options[:name]))
32
+ return puts("Can't wrap install with name #{options[:name]}")
33
+ end
34
+ file_string = "module #{mod_name}\n#{file_string}\nend"
35
+ File.open(filename, 'w') {|f| f.write file_string }
36
+ end
24
37
  puts "Saved to #{filename}."
25
38
  end
26
39
 
@@ -31,6 +44,6 @@ module Boson::Commands::WebCore #:nodoc:
31
44
 
32
45
  private
33
46
  def strip_name_from_url(url)
34
- url[/\/([^\/.]+)(\.[a-z]+)?$/, 1]
47
+ url[/\/([^\/.]+)(\.[a-z]+)?$/, 1].to_s.gsub('-', '_').gsub(/[^a-zA-Z_]/, '')
35
48
  end
36
49
  end
@@ -1,17 +1,11 @@
1
1
  require 'digest/md5'
2
2
  module Boson
3
+ # Used in all things indexing i.e. saving state for boson's commandline.
3
4
  module Index
4
5
  extend self
5
6
  attr_reader :libraries, :commands
6
7
 
7
- def read_and_transfer(ignored_libraries=[])
8
- read
9
- existing_libraries = (Boson.libraries.map {|e| e.name} + ignored_libraries).uniq
10
- Boson.libraries += @libraries.select {|e| !existing_libraries.include?(e.name)}
11
- existing_commands = Boson.commands.map {|e| e.name} #td: consider namespace
12
- Boson.commands += @commands.select {|e| !existing_commands.include?(e.name) && !ignored_libraries.include?(e.lib)}
13
- end
14
-
8
+ # Updates the index.
15
9
  def update(options={})
16
10
  options[:all] = true if !exists? && !options.key?(:all)
17
11
  libraries_to_update = options[:all] ? Runner.all_libraries : changed_libraries
@@ -25,23 +19,43 @@ module Boson
25
19
  write
26
20
  end
27
21
 
28
- def exists?
29
- File.exists? marshal_file
22
+ # Reads and initializes index.
23
+ def read
24
+ return if @read
25
+ @libraries, @commands, @lib_hashes = exists? ? Marshal.load(File.read(marshal_file)) : [[], [], {}]
26
+ delete_stale_libraries_and_commands
27
+ set_latest_namespaces
28
+ @read = true
30
29
  end
31
30
 
31
+ # Writes/saves current index to config/index.marshal.
32
32
  def write
33
33
  save_marshal_index Marshal.dump([Boson.libraries, Boson.commands, latest_hashes])
34
34
  end
35
35
 
36
+ #:stopdoc:
37
+ def read_and_transfer(ignored_libraries=[])
38
+ read
39
+ existing_libraries = (Boson.libraries.map {|e| e.name} + ignored_libraries).uniq
40
+ Boson.libraries += @libraries.select {|e| !existing_libraries.include?(e.name)}
41
+ existing_commands = Boson.commands.map {|e| e.name} #td: consider namespace
42
+ Boson.commands += @commands.select {|e| !existing_commands.include?(e.name) && !ignored_libraries.include?(e.lib)}
43
+ end
44
+
45
+ def exists?
46
+ File.exists? marshal_file
47
+ end
48
+
36
49
  def save_marshal_index(marshal_string)
37
50
  File.open(marshal_file, 'w') {|f| f.write marshal_string }
38
51
  end
39
52
 
40
- def read
41
- return if @read
42
- @libraries, @commands, @lib_hashes = exists? ? Marshal.load(File.read(marshal_file)) : [[], [], {}]
43
- set_latest_namespaces
44
- @read = true
53
+ def delete_stale_libraries_and_commands
54
+ cached_libraries = @lib_hashes.keys
55
+ libs_to_delete = @libraries.select {|e| !cached_libraries.include?(e.name) && e.is_a?(FileLibrary) }
56
+ names_to_delete = libs_to_delete.map {|e| e.name }
57
+ libs_to_delete.each {|e| @libraries.delete(e) }
58
+ @commands.delete_if {|e| names_to_delete.include? e.lib }
45
59
  end
46
60
 
47
61
  # get latest namespaces from config files
@@ -91,5 +105,6 @@ module Boson
91
105
  h
92
106
  }
93
107
  end
108
+ #:startdoc:
94
109
  end
95
110
  end
@@ -1,5 +1,5 @@
1
1
  module Boson
2
- # Scrapes and processes method metadata with the inspectors (MethodInspector, CommentInspector
2
+ # Scrapes and processes method attributes with the inspectors (MethodInspector, CommentInspector
3
3
  # and ArgumentInspector) and hands off the usable data to FileLibrary objects.
4
4
  module Inspector
5
5
  extend self
@@ -34,7 +34,7 @@ module Boson
34
34
  @enabled = false
35
35
  end
36
36
 
37
- # Adds method data scraped for the library's module to the library's commands.
37
+ # Adds method attributes scraped for the library's module to the library's commands.
38
38
  def add_method_data_to_library(library)
39
39
  @commands_hash = library.commands_hash
40
40
  @library_file = library.library_file
@@ -6,7 +6,7 @@ module Boson::ArgumentInspector
6
6
  # Returns same argument arrays as scrape_with_eval but argument defaults haven't been evaluated.
7
7
  def scrape_with_text(file_string, meth)
8
8
  tabspace = "[ \t]"
9
- if match = /^#{tabspace}*def#{tabspace}+#{meth}#{tabspace}*($|\(?\s*([^\)]+)\s*\)?\s*$)/.match(file_string)
9
+ if match = /^#{tabspace}*def#{tabspace}+#{meth}\b#{tabspace}*($|\(?\s*([^\)]+)\s*\)?\s*$)/.match(file_string)
10
10
  (match.to_a[2] || '').split(/\s*,\s*/).map {|e| e.split(/\s*=\s*/)}
11
11
  end
12
12
  end
@@ -20,7 +20,7 @@ module Boson::ArgumentInspector
20
20
  # def meth2(*args) -> [['*args']]
21
21
  def scrape_with_eval(meth, klass, object)
22
22
  unless %w[initialize].include?(meth.to_s)
23
- return if class << object; private_instance_methods(true) end.include?(meth.to_s)
23
+ return if class << object; private_instance_methods(true).map {|e| e.to_s } end.include?(meth.to_s)
24
24
  end
25
25
  params, values, arity, num_args = trace_method_args(meth, klass, object)
26
26
  return if local_variables == params # nothing new found
@@ -40,9 +40,9 @@ module Boson::ArgumentInspector
40
40
  [a << ["*#{x}"], i+1]
41
41
  else
42
42
  if arity < 0 && i >= arity.abs - 1
43
- [a << [x, values[i]], i + 1]
43
+ [a << [x.to_s, values[i]], i + 1]
44
44
  else
45
- [a << [x], i+1]
45
+ [a << [x.to_s], i+1]
46
46
  end
47
47
  end
48
48
  end.first
@@ -1,6 +1,6 @@
1
1
  module Boson
2
- # Scrapes comments right before a method for its metadata. Metadata attributes are the
3
- # same as MethodInspector: desc, options, render_options. Attributes must begin with '@' i.e.:
2
+ # Scrapes comments right before a method for its attributes. Metadata attributes are the
3
+ # same as MethodInspector : desc, options, render_options. Attributes must begin with '@' i.e.:
4
4
  #
5
5
  # # @desc Does foo
6
6
  # # @options :verbose=>true
@@ -1,9 +1,10 @@
1
1
  module Boson
2
- # Allows for defining method metadata with new_method_added and the
2
+ # Gathers method attributes with new_method_added and the
3
3
  # following Module methods:
4
- # * desc: Defines a description for a method/command
4
+ # * desc: Defines a description for a method/command.
5
5
  # * options: Defines an OptionParser object for a method's options.
6
- # * render_options: Defines an OptionParser object for a method's rendering options.
6
+ # * render_options: Defines an OptionParser object for a method's rendering options. These options
7
+ # are passed to View.render when rendering a command.
7
8
  #
8
9
  # These method calls must come immediately before a method i.e.:
9
10
  #
@@ -11,7 +12,7 @@ module Boson
11
12
  # options :verbose=>:boolean
12
13
  # def foo(options={})
13
14
  #
14
- # This module also allows for defining method metadata as comments. Although the actual
15
+ # This module also allows for defining method attributes as comments. Although the actual
15
16
  # scraping of comments is handled by CommentInspector, MethodInspector gather's the method
16
17
  # location it needs with with find_method_locations().
17
18
  module MethodInspector
@@ -21,7 +22,7 @@ module Boson
21
22
  @mod_store ||= {}
22
23
  METHODS = [:desc, :options, :render_options]
23
24
 
24
- # The method_added used while scraping method metadata.
25
+ # The method_added used while scraping method attributes.
25
26
  def new_method_added(mod, meth)
26
27
  return unless mod.name[/^Boson::Commands::/]
27
28
  self.current_module = mod
@@ -59,10 +60,11 @@ module Boson
59
60
  end
60
61
  end
61
62
 
63
+ CALLER_REGEXP = RUBY_VERSION < '1.9' ? /in `load_source'/ : /in `<module:.*>'/
62
64
  # Returns an array of the file and line number at which a method starts using
63
65
  # a caller array. Necessary information for CommentInspector to function.
64
66
  def find_method_locations(stack)
65
- if (line = stack.find {|e| e =~ /in `load_source'/ })
67
+ if (line = stack.find {|e| e =~ CALLER_REGEXP })
66
68
  (line =~ /^(.*):(\d+)/) ? [$1, $2.to_i] : nil
67
69
  end
68
70
  end
@@ -1,7 +1,64 @@
1
1
  module Boson
2
- # This library loads a file in the commands subdirectory of a Boson::Repo. This library looks for files
3
- # in repositories in the order given by Boson.repos.
4
- # TODO: explain file format, modules, inspectors
2
+ # This library is based on a file of the same name under the commands directory of a repository.
3
+ # Since there can be multiple repositories, a library's file is looked for in the order given by
4
+ # Boson.repos.
5
+ #
6
+ # To create this library, simply create a file with a module and some methods. Non-private methods
7
+ # are automatically loaded as a library's commands.
8
+ #
9
+ # Take for example a library brain.rb:
10
+ # module Brain
11
+ # def take_over(destination)
12
+ # puts "Pinky, it's time to take over the #{destination}!"
13
+ # end
14
+ # end
15
+ #
16
+ # Once loaded, this library can be run from the commandline or irb:
17
+ # bash> boson take_over world
18
+ # irb>> take_over 'world'
19
+ #
20
+ # If the library is namespaced, the command would be run as brain.take_over.
21
+ #
22
+ # Let's give Brain an option in his conquest:
23
+ # module Brain
24
+ # options :execute=>:string
25
+ # def take_over(destination, options={})
26
+ # puts "Pinky, it's time to take over the #{destination}!"
27
+ # system(options[:execute]) if options[:execute]
28
+ # end
29
+ # end
30
+ #
31
+ # From the commandline and irb this runs as:
32
+ # bash> boson take_over world -e initiate_brainiac
33
+ # irb>> take_over 'world -e initiate_brainiac'
34
+ #
35
+ # To learn more about the depth of option types available to a command, see OptionParser.
36
+ #
37
+ # Since boson aims to make your libraries just standard ruby, we can achieve the above
38
+ # by placing options in comments above a method:
39
+ # module Brain
40
+ # # @options :execute=>:string
41
+ # # Help Brain live the dream
42
+ # def take_over(destination, options={})
43
+ # puts "Pinky, it's time to take over the #{destination}!"
44
+ # system(options[:execute]) if options[:execute]
45
+ # end
46
+ # end
47
+ #
48
+ # Some points about the above:
49
+ # * A '@' must prefix options and other method calls that become comments.
50
+ # * Note the comment above the method. One-line comments right before a method set a command's description.
51
+ # * See MethodInspector for other command attributes, like options, that can be placed above a method.
52
+ # * See CommentInspector for the rules about commenting command attributes.
53
+ #
54
+ # Once a command has a defined option, a command can also recognize a slew of global options:
55
+ # irb>> take_over '-h'
56
+ # take_over [destination] [--execute=STRING]
57
+ #
58
+ # # prints much more verbose help
59
+ # irb>> take_over '-hv'
60
+ #
61
+ # For more about these global options see Scientist.
5
62
  class FileLibrary < Library
6
63
  #:stopdoc:
7
64
  def self.library_file(library, dir)