boson 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -6,20 +6,30 @@ Works with Ruby 1.8.6 and 1.9.1.
6
6
  Note: To read a linkable version of this README, {see here}[http://tagaholic.me/boson/doc/].
7
7
 
8
8
  == Features
9
- * Commands are just methods extended for a given object, the default being the top level object, main.
9
+ * Simple organization: Commands are just methods on an object (default is main) and command libraries are just modules.
10
10
  * Commands are accessible from the commandline (Boson::BinRunner) or irb (Boson::ConsoleRunner).
11
- * Command libraries, which are just modules, are written in non-dsl ruby which allows for easy testing
12
- and use outside of boson (Boson::FileLibrary).
11
+ * Libraries
12
+ * can be written in plain ruby which allows for easy testing and use independent of boson (Boson::FileLibrary).
13
+ * can exist locally as a Bosonfile (Boson::LocalFileLibrary) and under lib/boson/commands or .boson/commands.
14
+ * can be made from gems (Boson::GemLibrary) or any require-able file (Boson::RequireLibrary).
15
+ * are encouraged to be shared. Libraries can be installed with a given url. Users can customize any aspect of a third-party
16
+ library without modifying it (Boson::Library).
17
+ * Commands
18
+ * can have any number of local and global options (Boson::OptionCommand). Options are defined with Boson::OptionParser.
19
+ * can have any view associated to it (via Hirb) without adding view code to the command's method.
20
+ These views can be toggled on and manipulated via global render options (Boson::View and Boson::OptionCommand).
21
+ * can pipe their return value into multiple commands with pipe options. Default pipe options give the ability
22
+ to search and sort an array of any objects (Boson::Pipe).
23
+ * Option parser (Boson::OptionParser)
24
+ * provides option types that map to objects i.e. :array type creates Array objects.
25
+ * come with 5 default option types: boolean, array, string, hash and numeric.
26
+ * can have have custom option types defined by users (Boson::Options).
13
27
  * Comes with default commands to load, search, list and install commands and libraries (Boson::Commands::Core).
14
- * Commands can be full-blown commandline apps thanks to powerful options (Boson::OptionParser)
15
- and hirb's views.
16
- * There are 5 default option types: boolean, array, string, hash and numeric. Custom option types
17
- can be defined to map to any Ruby class with one method (Boson::Options).
18
- * Commands can have views toggled without adding view code to the original command (Boson::Scientist).
19
- * Command libraries are social as a user can install them from a url and then customize command
20
- names and options without changing the original library.
21
28
  * Namespaces are optional and when used are methods which allow for method_missing magic.
22
29
 
30
+ == Creating Command Libraries
31
+ See Boson::FileLibrary or here[http://tagaholic.me/boson/doc/classes/Boson/FileLibrary.html].
32
+
23
33
  == Irb Example
24
34
 
25
35
  To use in irb, drop this in your ~/.irbrc:
@@ -132,14 +142,11 @@ Having done that, let's start up irb:
132
142
 
133
143
  # Sweet! Now we have a list and description of commands that come with irb.
134
144
 
135
- == Creating Command Libraries
136
- See Boson::FileLibrary or here[http://tagaholic.me/boson/doc/classes/Boson/FileLibrary.html].
137
-
138
145
  == Todo
139
146
  * More tests
140
147
  * Making commands out of existing gems easier and more powerful
141
- * Better local repositories, perhaps a BosonFile
142
148
  * Consider managing extensions to core and standard libraries
149
+ * Features based on commands and their argument types i.e. aliasing, completion, piping
143
150
  * Consider dropping alias gem dependency if not using its full potential
144
151
 
145
152
  == Bugs/Issues
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 0
3
3
  :minor: 2
4
- :patch: 0
4
+ :patch: 1
data/lib/boson.rb CHANGED
@@ -3,9 +3,9 @@ $:.unshift File.dirname(__FILE__) unless $:.include? File.expand_path(File.dirna
3
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
- %w{module file gem require}.each {|e| require "boson/libraries/#{e}_library" }
6
+ %w{module file gem require local_file}.each {|e| require "boson/libraries/#{e}_library" }
7
7
  (%w{namespace view command util commands option_parser options} +
8
- %w{index scientist}).each {|e| require "boson/#{e}" }
8
+ %w{index repo_index scientist option_command pipe}).each {|e| require "boson/#{e}" }
9
9
 
10
10
  # This module stores the libraries, commands, repos and main object used throughout Boson.
11
11
  #
@@ -17,7 +17,6 @@ $:.unshift File.dirname(__FILE__) unless $:.include? File.expand_path(File.dirna
17
17
  # * Boson::FileLibrary - Explains creating libraries as files
18
18
  # * Boson::Loader - Explains library module callbacks
19
19
  # * Boson::OptionParser - All about options
20
- # * Boson::Scientist - Explains how commands can be both shell-commands and normal ruby methods
21
20
  module Boson
22
21
  # Module which is extended by Boson.main_object to give it command functionality.
23
22
  module Universe; include Commands::Namespace; end
@@ -45,13 +44,14 @@ module Boson
45
44
  # An optional local repository which defaults to ./lib/boson or ./.boson.
46
45
  def local_repo
47
46
  @local_repo ||= begin
47
+ ignored_dirs = (repo.config[:ignore_directories] || []).map {|e| File.expand_path(e) }
48
48
  dir = ["lib/boson", ".boson"].find {|e| File.directory?(e) &&
49
- File.expand_path(e) != repo.dir }
49
+ File.expand_path(e) != repo.dir && !ignored_dirs.include?(File.expand_path('.')) }
50
50
  Repo.new(dir) if dir
51
51
  end
52
52
  end
53
53
 
54
- # The array of loaded repositories
54
+ # The array of loaded repositories containing the main repo and a possible local repo
55
55
  def repos
56
56
  @repos ||= [repo, local_repo].compact
57
57
  end
data/lib/boson/command.rb CHANGED
@@ -24,28 +24,27 @@ module Boson
24
24
  # and :lib are required keys.
25
25
  #
26
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.
35
- # * *:default_option* Only for an option command that has one argument. This treats the given
36
- # option as an optional first argument. Example:
37
- # # For a command with default option 'query' and options --query and -v
38
- # 'some -v' -> '--query=some -v'
39
- # '-v' -> '-v'
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
+ # [*:global_options*] Boolean to enable using global options without having to define render_options or options.
32
+ # [*:args*] Should only be set if not automatically set. This attribute is only
33
+ # important for commands that have options/render_options. Its value can be an array
34
+ # (as ArgumentInspector.scrape_with_eval produces), a number representing
35
+ # the number of arguments or '*' if the command has a variable number of arguments.
36
+ # [*:default_option*] Only for an option command that has one or zero arguments. This treats the given
37
+ # option as an optional first argument. Example:
38
+ # # For a command with default option 'query' and options --query and -v
39
+ # 'some -v' -> '--query=some -v'
40
+ # '-v' -> '-v'
40
41
  def initialize(hash)
41
42
  @name = hash[:name] or raise ArgumentError
42
43
  @lib = hash[:lib] or raise ArgumentError
43
- @alias = hash[:alias] if hash[:alias]
44
- @description = hash[:description] if hash[:description]
45
- @render_options = hash[:render_options] if hash[:render_options]
46
- @options = hash[:options] if hash[:options]
47
- @namespace = hash[:namespace] if hash[:namespace]
48
- @default_option = hash[:default_option] if hash[:default_option]
44
+ [:alias, :description, :render_options, :options, :namespace, :default_option,
45
+ :global_options].each do |e|
46
+ instance_variable_set("@#{e}", hash[e]) if hash[e]
47
+ end
49
48
  if hash[:args]
50
49
  if hash[:args].is_a?(Array)
51
50
  @args = hash[:args]
@@ -75,7 +74,7 @@ module Boson
75
74
 
76
75
  # Option parser for command as defined by @options.
77
76
  def option_parser
78
- @option_parser ||= (@options ? OptionParser.new(@options) : nil)
77
+ @option_parser ||= OptionParser.new(@options || {})
79
78
  end
80
79
 
81
80
  # Help string for options if a command has it.
@@ -107,7 +106,7 @@ module Boson
107
106
  end
108
107
 
109
108
  def option_command?
110
- options || render_options
109
+ options || render_options || @global_options
111
110
  end
112
111
 
113
112
  def arg_size
@@ -24,7 +24,7 @@ module Boson::Commands::Core #:nodoc:
24
24
  :fields=>{:default=>[:name, :commands, :gems, :library_type], :values=>library_attributes},
25
25
  :filters=>{:default=>{:gems=>[:join, ','],:commands=>:size}, :desc=>"Filters to apply to library fields" }}
26
26
  },
27
- 'load_library'=>{:description=>"Load/reload a library", :options=>{:reload=>:boolean, [:verbose,:V]=>true}}
27
+ 'load_library'=>{:description=>"Load a library", :options=>{[:verbose,:V]=>true}}
28
28
  }
29
29
 
30
30
  {:namespace=>false, :library_file=>File.expand_path(__FILE__), :commands=>commands}
@@ -39,8 +39,7 @@ module Boson::Commands::Core #:nodoc:
39
39
  end
40
40
 
41
41
  def load_library(library, options={})
42
- options[:reload] ? Boson::Manager.reload(library, options) :
43
- Boson::Manager.load(library, options)
42
+ Boson::Manager.load(library, options)
44
43
  end
45
44
 
46
45
  def render(object, options={})
@@ -56,11 +55,11 @@ module Boson::Commands::Core #:nodoc:
56
55
  puts msg
57
56
  if command && options[:verbose]
58
57
  if command.options && !command.options.empty?
59
- puts "\nCOMMAND OPTIONS"
58
+ puts "\nLOCAL OPTIONS"
60
59
  command.option_parser.print_usage_table
61
60
  end
62
- puts "\nGLOBAL/RENDER OPTIONS"
63
- Boson::Scientist.render_option_parser(command).print_usage_table
61
+ puts "\nGLOBAL OPTIONS"
62
+ Boson::Scientist.option_command(command).option_parser.print_usage_table
64
63
  end
65
64
  end
66
65
  end
data/lib/boson/index.rb CHANGED
@@ -1,118 +1,41 @@
1
- require 'digest/md5'
2
1
  module Boson
3
- # This class is used by BinRunner to index/store all of Boson's commands and libraries. When this index updates,
4
- # it detects library files whose md5 hash have changed and reindexes them. The index is stored with Marshal
5
- # at ~/.boson/config/index.marshal. Since the index is marshaled, putting lambdas/procs in it will break it.
6
- # If your index gets corrupted, simply delete it and next time Boson needs it, the index will be recreated.
2
+ # This class manages indexing/storing all commands and libraries. See RepoIndex for details
3
+ # about the index created for each Repo.
7
4
  module Index
8
5
  extend self
9
- attr_reader :libraries, :commands
10
-
11
- # Updates the index.
12
- def update(options={})
13
- libraries_to_update = !exists? ? Runner.all_libraries : options[:libraries] || changed_libraries
14
- read_and_transfer(libraries_to_update)
15
- if options[:verbose]
16
- puts !exists? ? "Generating index for all #{libraries_to_update.size} libraries. Patience ... is a bitch" :
17
- (libraries_to_update.empty? ? "No libraries indexed" :
18
- "Indexing the following libraries: #{libraries_to_update.join(', ')}")
19
- end
20
- Manager.failed_libraries = []
21
- unless libraries_to_update.empty?
22
- Manager.load(libraries_to_update, options.merge(:index=>true))
23
- unless Manager.failed_libraries.empty?
24
- $stderr.puts("Error: These libraries failed to load while indexing: #{Manager.failed_libraries.join(', ')}")
25
- end
26
- end
27
- write(Manager.failed_libraries)
28
- end
29
-
30
- # Reads and initializes index.
31
- def read
32
- return if @read
33
- @libraries, @commands, @lib_hashes = exists? ? Marshal.load(File.read(marshal_file)) : [[], [], {}]
34
- delete_stale_libraries_and_commands
35
- set_command_namespaces
36
- @read = true
6
+ # Array of indexes, one per repo in Boson.repos.
7
+ def indexes
8
+ @indexes ||= Boson.repos.map {|e| RepoIndex.new(e) }
37
9
  end
38
10
 
39
- # Writes/saves current index to config/index.marshal.
40
- def write(failed_libraries=[])
41
- latest = latest_hashes
42
- failed_libraries.each {|e| latest.delete(e) }
43
- save_marshal_index Marshal.dump([Boson.libraries, Boson.commands, latest])
11
+ # Updates all repo indexes.
12
+ def update(options={})
13
+ indexes.each {|e| e.update(options) }
44
14
  end
45
15
 
46
16
  #:stopdoc:
47
- def read_and_transfer(ignored_libraries=[])
48
- read
49
- existing_libraries = (Boson.libraries.map {|e| e.name} + ignored_libraries).uniq
50
- libraries_to_add = @libraries.select {|e| !existing_libraries.include?(e.name)}
51
- Boson.libraries += libraries_to_add
52
- # depends on saved commands being correctly associated with saved libraries
53
- Boson.commands += libraries_to_add.map {|e| e.command_objects(e.commands, @commands) }.flatten
54
- end
55
-
56
- def exists?
57
- File.exists? marshal_file
58
- end
59
-
60
- def save_marshal_index(marshal_string)
61
- File.open(marshal_file, 'w') {|f| f.write marshal_string }
62
- end
63
-
64
- def delete_stale_libraries_and_commands
65
- cached_libraries = @lib_hashes.keys
66
- libs_to_delete = @libraries.select {|e| !cached_libraries.include?(e.name) && e.is_a?(FileLibrary) }
67
- names_to_delete = libs_to_delete.map {|e| e.name }
68
- libs_to_delete.each {|e| @libraries.delete(e) }
69
- @commands.delete_if {|e| names_to_delete.include? e.lib }
17
+ def read
18
+ indexes.each {|e| e.read }
70
19
  end
71
20
 
72
- # set namespaces for commands
73
- def set_command_namespaces
74
- lib_commands = @commands.inject({}) {|t,e| (t[e.lib] ||= []) << e; t }
75
- namespace_libs = @libraries.select {|e| e.namespace(e.indexed_namespace) }
76
- namespace_libs.each {|lib|
77
- (lib_commands[lib.name] || []).each {|e| e.namespace = lib.namespace }
21
+ def find_library(command)
22
+ indexes.each {|e|
23
+ lib = e.find_library(command)
24
+ return lib if lib
78
25
  }
26
+ nil
79
27
  end
80
28
 
81
- def namespaces
82
- nsps = @libraries.map {|e| e.namespace }.compact
83
- nsps.delete(false)
84
- nsps
85
- end
86
-
87
- def all_main_methods
88
- @commands.reject {|e| e.namespace }.map {|e| [e.name, e.alias]}.flatten.compact + namespaces
89
- end
90
-
91
- def marshal_file
92
- File.join(Boson.repo.config_dir, 'index.marshal')
93
- end
94
-
95
- def find_library(command)
96
- read
97
- namespace_command = command.split('.')[0]
98
- if (lib = @libraries.find {|e| e.namespace == namespace_command })
99
- lib.name
100
- elsif (cmd = Command.find(command, @commands))
101
- cmd.lib
102
- end
29
+ def commands
30
+ indexes.map {|e| e.commands}.flatten
103
31
  end
104
32
 
105
- def changed_libraries
106
- read
107
- latest_hashes.select {|lib, hash| @lib_hashes[lib] != hash}.map {|e| e[0]}
33
+ def libraries
34
+ indexes.map {|e| e.libraries}.flatten
108
35
  end
109
36
 
110
- def latest_hashes
111
- Runner.all_libraries.inject({}) {|h, e|
112
- lib_file = FileLibrary.library_file(e, Boson.repo.dir)
113
- h[e] = Digest::MD5.hexdigest(File.read(lib_file)) if File.exists?(lib_file)
114
- h
115
- }
37
+ def all_main_methods
38
+ indexes.map {|e| e.all_main_methods}.flatten
116
39
  end
117
40
  #:startdoc:
118
41
  end
@@ -1,6 +1,28 @@
1
1
  module Boson
2
2
  # Scrapes and processes method attributes with the inspectors (MethodInspector, CommentInspector
3
- # and ArgumentInspector) and hands off the usable data to FileLibrary objects.
3
+ # and ArgumentInspector) and hands off the data to FileLibrary objects.
4
+ #
5
+ # === Method Attributes
6
+ # Method attributes refer to (commented) Module methods placed before a command's method
7
+ # in a FileLibrary module:
8
+ # module SomeMod
9
+ # # @render_options :fields=>%w{one two}
10
+ # # @config :alias=>'so'
11
+ # options :verbose=>:boolean
12
+ # # Something descriptive perhaps
13
+ # def some_method(opts)
14
+ # # ...
15
+ # end
16
+ # end
17
+ #
18
+ # Method attributes serve as configuration for a method's command. Available method attributes:
19
+ # * config: Hash to define any command attributes (see Command.new).
20
+ # * desc: String to define a command's description for a command. Defaults to first commented line above a method.
21
+ # * options: Hash to define an OptionParser object for a command's options.
22
+ # * render_options: Hash to define an OptionParser object for a command's local/global render options (see View).
23
+ #
24
+ # When deciding whether to use commented or normal Module methods, remember that commented Module methods allow
25
+ # independence from Boson (useful for testing). See CommentInspector for more about commented method attributes.
4
26
  module Inspector
5
27
  extend self
6
28
  attr_reader :enabled
@@ -57,7 +79,11 @@ module Boson
57
79
 
58
80
  def add_scraped_data_to_config(key, value, cmd)
59
81
  if value.is_a?(Hash)
60
- @commands_hash[cmd][key] = Util.recursive_hash_merge value, @commands_hash[cmd][key] || {}
82
+ if key == :config
83
+ @commands_hash[cmd] = Util.recursive_hash_merge value, @commands_hash[cmd]
84
+ else
85
+ @commands_hash[cmd][key] = Util.recursive_hash_merge value, @commands_hash[cmd][key] || {}
86
+ end
61
87
  else
62
88
  @commands_hash[cmd][key] ||= value
63
89
  end
@@ -1,25 +1,23 @@
1
1
  module Boson
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
- #
2
+ # Scrapes comments right before a method for its attributes. Method attributes must begin with '@' i.e.:
5
3
  # # @desc Does foo
6
4
  # # @options :verbose=>true
7
5
  # def foo(options={})
8
6
  #
9
- # Some rules about comment attributes:
10
- # * Attribute definitions can span multiple lines. When a new attribute starts a line or the comments end
7
+ # Some rules about these attributes:
8
+ # * Attribute definitions can span multiple lines. When a new attribute starts a line or the comments end,
11
9
  # then a definition ends.
12
10
  # * If no @desc is found in the comment block, then the first comment line directly above the method
13
11
  # is assumed to be the value for @desc. This means that no multi-line attribute definitions can occur
14
12
  # without a description since the last line is assumed to be a description.
15
- # * options and render_options attributes can take any valid ruby since they're evaled in their module's context.
13
+ # * options, config and render_options attributes can take any valid ruby since they're evaled in their module's context.
16
14
  # * desc attribute is not evaled and is simply text to be set as a string.
17
15
  #
18
16
  # This module was inspired by
19
17
  # {pragdave}[http://github.com/pragdavespc/rake/commit/45231ac094854da9f4f2ac93465ed9b9ca67b2da].
20
18
  module CommentInspector
21
19
  extend self
22
- EVAL_ATTRIBUTES = [:options, :render_options]
20
+ EVAL_ATTRIBUTES = [:options, :render_options, :config]
23
21
 
24
22
  # Given a method's file string, line number and defining module, returns a hash
25
23
  # of attributes defined for that method.
@@ -1,26 +1,13 @@
1
1
  module Boson
2
- # Gathers method attributes with new_method_added and the
3
- # following Module methods:
4
- # * desc: Defines a description for a method/command.
5
- # * options: Defines an OptionParser object for a method's 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.
8
- #
9
- # These method calls must come immediately before a method i.e.:
10
- #
11
- # desc "Does foo"
12
- # options :verbose=>:boolean
13
- # def foo(options={})
14
- #
15
- # This module also allows for defining method attributes as comments. Although the actual
16
- # scraping of comments is handled by CommentInspector, MethodInspector gather's the method
17
- # location it needs with with find_method_locations().
2
+ # Gathers method attributes by redefining method_added and capturing method
3
+ # calls before a method. This module also saves method locations so CommentInspector
4
+ # can scrape their commented method attributes.
18
5
  module MethodInspector
19
6
  extend self
20
7
  attr_accessor :current_module
21
8
  attr_reader :mod_store
22
9
  @mod_store ||= {}
23
- METHODS = [:desc, :options, :render_options]
10
+ METHODS = [:config, :desc, :options, :render_options]
24
11
 
25
12
  # The method_added used while scraping method attributes.
26
13
  def new_method_added(mod, meth)
@@ -1,12 +1,16 @@
1
1
  module Boson
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
2
+ # This class loads a file by its path relative to the commands directory of a repository.
3
+ # For example the library 'public/misc' could refer to the file '~/.boson/commands/public/misc.rb'.
4
+ # If a file's basename is unique in its repository, then it can be loaded with its basename i.e. 'misc'
5
+ # for the previous example. When loading a library, this class searches repositories in the order given by
4
6
  # Boson.repos.
5
7
  #
6
- # To create this library, simply create a file with a module and some methods (See Library
7
- # for naming a module). Non-private methods are automatically loaded as a library's commands.
8
+ # === Creating a FileLibrary
9
+ # Start by creating a file with a module and some methods (See Library for naming a module).
10
+ # Non-private methods are automatically loaded as a library's commands.
8
11
  #
9
12
  # Take for example a library brain.rb:
13
+ # # Drop this in ~/.boson/commands/brain.rb
10
14
  # module Brain
11
15
  # def take_over(destination)
12
16
  # puts "Pinky, it's time to take over the #{destination}!"
@@ -32,10 +36,8 @@ module Boson
32
36
  # bash> boson take_over world -e initiate_brainiac
33
37
  # irb>> take_over 'world -e initiate_brainiac'
34
38
  #
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
+ # Since Boson aims to make your libraries just standard ruby, we can achieve the above
40
+ # by making options a commented method attribute:
39
41
  # module Brain
40
42
  # # @options :execute=>:string
41
43
  # # Help Brain live the dream
@@ -46,10 +48,9 @@ module Boson
46
48
  # end
47
49
  #
48
50
  # Some points about the above:
49
- # * A '@' must prefix options and other method calls that become comments.
51
+ # * A '@' must prefix options and other method attributes that become comments.
50
52
  # * 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
+ # * See Inspector for other method attributes, like config and render_options, that can be placed above a method.
53
54
  #
54
55
  # Once a command has a defined option, a command can also recognize a slew of global options:
55
56
  # irb>> take_over '-h'
@@ -58,7 +59,7 @@ module Boson
58
59
  # # prints much more verbose help
59
60
  # irb>> take_over '-hv'
60
61
  #
61
- # For more about these global options see Scientist.
62
+ # For more about these global options see OptionCommand and View.
62
63
  class FileLibrary < Library
63
64
  #:stopdoc:
64
65
  def self.library_file(library, dir)
@@ -75,8 +76,7 @@ module Boson
75
76
 
76
77
  def self.reset_file_cache(name=nil)
77
78
  if name && @file_cache
78
- #td: tia other repos
79
- @file_cache.delete(library_file(name, Boson.repo.dir))
79
+ @file_cache.delete(library_file(name, (matched_repo || Boson.repo).dir))
80
80
  else
81
81
  @file_cache = nil
82
82
  end
@@ -101,14 +101,17 @@ module Boson
101
101
  def set_name(name)
102
102
  @lib_file = File.exists?(library_file(name.to_s)) ? library_file(name.to_s) :
103
103
  Dir[self.class.matched_repo.commands_dir.to_s+'/**/*.rb'].find {|e| e =~ /\/#{name}\.rb$/}
104
- super @lib_file.gsub(/^#{self.class.matched_repo.commands_dir}\/|\.rb$/, '')
104
+ @lib_file.gsub(/^#{self.class.matched_repo.commands_dir}\/|\.rb$/, '')
105
+ end
106
+
107
+ def base_module
108
+ @base_module ||= @name.include?('/') ? create_module_from_path : Commands
105
109
  end
106
110
 
107
111
  def load_source(reload=false)
108
112
  library_string = self.class.read_library_file(@lib_file, reload)
109
- @base_module = @name.include?('/') ? create_module_from_path : Commands
110
113
  Inspector.enable
111
- @base_module.module_eval(library_string, @lib_file)
114
+ base_module.module_eval(library_string, @lib_file)
112
115
  Inspector.disable
113
116
  end
114
117
 
@@ -123,15 +126,7 @@ module Boson
123
126
  detected = detect_additions(:modules=>true) { load_source }
124
127
  @module = determine_lib_module(detected[:modules]) unless @module
125
128
  #without this, module's class methods weren't showing up
126
- @module = Util.constantize(@module) if @base_module != Commands
127
- end
128
-
129
- def reload_source_and_set_module
130
- detected = detect_additions(:modules=>true) { load_source(true) }
131
- if (@new_module = !detected[:modules].empty?)
132
- @commands = []
133
- @module = determine_lib_module(detected[:modules])
134
- end
129
+ @module = Util.constantize(@module) if base_module != Commands
135
130
  end
136
131
 
137
132
  def determine_lib_module(detected_modules)
@@ -140,7 +135,7 @@ module Boson
140
135
  when 0 then raise LoaderError, "Can't detect module. Make sure at least one module is defined in the library."
141
136
  else
142
137
  unless (lib_module = Util.constantize("boson/commands/#{@name}")) && lib_module.to_s[/^Boson::Commands/]
143
- command_modules = detected_modules.map {|e| e.to_s}.grep(/^#{@base_module}::/)
138
+ command_modules = detected_modules.map {|e| e.to_s}.grep(/^#{base_module}::/)
144
139
  unless command_modules.size == 1 && (lib_module = command_modules[0])
145
140
  raise LoaderError, "Can't detect module. Specify a module in this library's config."
146
141
  end