Module: Kernel
- Defined in:
- lib/qualitysmith_extensions/kernel/die.rb,
lib/qualitysmith_extensions/object/default.rb,
lib/qualitysmith_extensions/kernel/backtrace.rb,
lib/qualitysmith_extensions/kernel/autoreload.rb,
lib/qualitysmith_extensions/kernel/trap_chain.rb,
lib/qualitysmith_extensions/kernel/require_all.rb,
lib/qualitysmith_extensions/global_variable_set.rb,
lib/qualitysmith_extensions/kernel/remove_const.rb,
lib/qualitysmith_extensions/kernel/require_once.rb,
lib/qualitysmith_extensions/module/remove_const.rb,
lib/qualitysmith_extensions/kernel/remove_module.rb,
lib/qualitysmith_extensions/kernel/capture_output.rb,
lib/qualitysmith_extensions/kernel/windows_platform.rb
Overview
–
- Author
-
Tyler Rick
- Copyright
-
Copyright © 2007 QualitySmith, Inc.
- License
-
Ruby License
- Submit to Facets?
-
No, too ugly and unreliable.
++
Instance Method Summary collapse
-
#autoreload(*args) ⇒ Object
Autoreload feature files.
-
#autoreload_files(*args) ⇒ Object
(also: #autoreload_glob)
Same as #autoreload, but does not include previously loaded features.
-
#backtrace ⇒ Object
Equivalent to calling caller(0).
-
#backtrace_using_exception ⇒ Object
I thought I ran into some case where it didn’t work to use caller(0)…which prompted me to do it this way (raise and rescue an exception)…but now I can’t duplicate that problem, so I will deprecate this method.
-
#capture_output(output_streams = $stdout, &block) ⇒ Object
Captures the output (stdout by default) that
block
tries to generate and returns it as a string. - #default!(object, default_value) ⇒ Object
- #die(message, exit_code = 1) ⇒ Object
-
#global_variable_get(var, options = {}) ⇒ Object
Gets the global variable
var
, which can either be a symbol or an actual global variable (use:match_object
). -
#global_variable_name(var) ⇒ Object
Looks up the name of global variable
var
, which must be an actual global variable. -
#global_variable_set(var, value, options = {}) ⇒ Object
Sets the global variable
var
, which can either be a symbol or an actual global variable (use:match_object
). -
#pretty_backtrace ⇒ Object
Returns a human-readable backtrace.
-
#remove_const(const_name) ⇒ Object
This is similar to the built-in
Module#remove_const
, but it is accessible from all “levels” (because it is defined inKernel
) and can handle hierarchy. -
#remove_const! ⇒ Object
This is similar to Kernel#remove_const, but it only works for modules/classes.
-
#remove_module(const) ⇒ Object
This is similar to
remove_const
, but it only works for modules/classes. -
#require_all(what, options = {}) ⇒ Object
require
s all Ruby files specified bywhat
, but not matching any of the exclude filters. -
#require_local_all(dir = './', options = {}) ⇒ Object
require
s all Ruby files indir
(relative toFile.dirname(__FILE__)
) or any of its subdirectories. -
#require_once(name) ⇒ Object
Fixes bug in Ruby (1.8, at least – not sure if 2.0 fixes it) where a file can be required twice if the path is spelled differently.
-
#trap_chain(signal_name, *args, &block) ⇒ Object
Calling
Kernel#trap()
by itself will replace any previously registered handler code. - #windows_platform? ⇒ Boolean
Instance Method Details
#autoreload(*args) ⇒ Object
Autoreload feature files.
Automatically reload, at regular intervals, any previously loaded features, and/or other files not already loaded, if they have been modified since the last interval check. A numeric parameter sets the reload interval in seconds and the file parameter can either be a glob string or an array of file paths. If a glob string, it is expanded only once on the initial method call. Supplying a boolean parameter of ‘false’ will force autreload to skip previously loaded features and only reload the specified files. Also keeps a “dirty” flag.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/qualitysmith_extensions/kernel/autoreload.rb', line 17 def autoreload( *args ) check_interval=10 include_features = true files = nil args.each do |arg| case arg when Numeric check_interval = arg when String files = Dir.glob( arg ) when Array files = arg when TrueClass, FalseClass include_features = arg end end file_mtime = {} Thread.new(Time.now) do |start_time| loop do sleep check_interval if include_features feature_files = $LOADED_FEATURES.collect { |feature| $LOAD_PATH.each { |lp| file = File.join(lp, feature) } }.flatten p feature_files feature_files.each { |file| if File.exists?(file) and (mtime = File.stat(file).mtime) > (file_mtime[file] || start_time) $autoreload_dirty = true file_mtime[file] = mtime STDERR.puts "File '#{ file }' reloaded" begin load(file) rescue Exception => e STDERR.puts e.inspect end end } end if files files.each do |file| if File.exists?(file) and (mtime = File.stat(file).mtime) > (file_mtime[file] || start_time) $autoreload_dirty = true file_mtime[file] = mtime STDERR.puts "File '#{ file }' changed" begin load(file) rescue Exception => e STDERR.puts e.inspect end end end end end end end |
#autoreload_files(*args) ⇒ Object Also known as: autoreload_glob
Same as #autoreload, but does not include previously loaded features. This is equivalent to as adding a ‘false’ parameter to #autoreload.
86 87 88 |
# File 'lib/qualitysmith_extensions/kernel/autoreload.rb', line 86 def autoreload_files( *args ) autoreload( false, *args ) end |
#backtrace ⇒ Object
Equivalent to calling caller(0)
13 14 15 16 |
# File 'lib/qualitysmith_extensions/kernel/backtrace.rb', line 13 def backtrace full_backtrace = caller(0) return full_backtrace[1..-1] # We don't want this call to backtrace showing up in the backtrace, so skip top 1 frame. end |
#backtrace_using_exception ⇒ Object
I thought I ran into some case where it didn’t work to use caller(0)…which prompted me to do it this way (raise and rescue an exception)…but now I can’t duplicate that problem, so I will deprecate this method.
25 26 27 28 29 30 31 32 |
# File 'lib/qualitysmith_extensions/kernel/backtrace.rb', line 25 def backtrace_using_exception begin raise "Where am I?" rescue Exception => exception full_backtrace = exception.backtrace return full_backtrace[1..-1] # We don't want this call to backtrace showing up in the backtrace, so skip top 1 frame. end end |
#capture_output(output_streams = $stdout, &block) ⇒ Object
Captures the output (stdout by default) that block
tries to generate and returns it as a string.
output = capture_output($stderr) { noisy_command }
output = capture_output([$stdout, $stderr]) do
noisy_command
end
Note: If you specify more than one output stream, the entire results of each will be concatenated in the order you listed them, not necessarily in the order that you wrote to those streams.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/qualitysmith_extensions/kernel/capture_output.rb', line 35 def capture_output(output_streams = $stdout, &block) output_streams = [output_streams] unless output_streams.is_a? Array saved_output_streams = Dictionary.new output_streams.each do |output_stream| case output_stream.object_id when $stdout.object_id saved_output_streams[:$stdout] = $stdout $stdout = StringIO.new when $stderr.object_id saved_output_streams[:$stderr] = $stderr $stderr = StringIO.new end end what_they_tried_to_output = '' begin yield rescue Exception raise ensure saved_output_streams.each do |name, output_stream| case name when :$stdout what_they_tried_to_output += $stdout.string when :$stderr what_they_tried_to_output += $stderr.string end # Restore the original output_stream that we saved. case name when :$stdout $stdout = saved_output_streams[:$stdout] when :$stderr $stderr = saved_output_streams[:$stderr] end end end return what_they_tried_to_output end |
#default!(object, default_value) ⇒ Object
9 10 11 12 13 14 15 16 |
# File 'lib/qualitysmith_extensions/object/default.rb', line 9 def default!(object, default_value) case object when NilClass #object.become default_value #object.replace default_value else end end |
#die(message, exit_code = 1) ⇒ Object
10 11 12 13 |
# File 'lib/qualitysmith_extensions/kernel/die.rb', line 10 def die(, exit_code = 1) $stderr.puts exit exit_code end |
#global_variable_get(var, options = {}) ⇒ Object
Gets the global variable var
, which can either be a symbol or an actual global variable (use :match_object
).
global_variable_get(:$a)
global_variable_get($a, :match_object => true)
12 13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/qualitysmith_extensions/global_variable_set.rb', line 12 def global_variable_get(var, = {}) if .delete(:match_object) return global_variable_get(global_variable_name(var), ) else if var.is_a? Symbol raise NameError.new("#{var} is not a valid global variable name") unless var.to_s[0..0] == '$' return eval("#{var}") else raise ArgumentError.new("var must be a symbol unless :match_object => true") end end end |
#global_variable_name(var) ⇒ Object
Looks up the name of global variable var
, which must be an actual global variable.
global_variable_name($a)
27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/qualitysmith_extensions/global_variable_set.rb', line 27 def global_variable_name(var) global_variables.each do |test_var| #if eval(test_var).eql?(var) if eval(test_var).object_id == var.object_id #$stderr.puts "Checking #{test_var}. #{eval(test_var).inspect}" #$stderr.puts " #{$stdout.inspect}" return test_var.to_sym end end raise ArgumentError.new("The given object (#{var.inspect}) (#{var.object_id}) is not a valid global variable") end |
#global_variable_set(var, value, options = {}) ⇒ Object
Sets the global variable var
, which can either be a symbol or an actual global variable (use :match_object
).
global_variable_set(:$a, 'new')
global_variable_set($a, 'new', :match_object => true)
global_variable_set(:$a, "StringIO.new", :eval_string => true)
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/qualitysmith_extensions/global_variable_set.rb', line 43 def global_variable_set(var, value, = {}) #puts "global_variable_set(#{var}, #{value.inspect}, #{options.inspect}" if .delete(:match_object) return global_variable_set(global_variable_name(var), value, ) else if var.is_a? Symbol raise NameError.new("#{var} is not a valid global variable name") unless var.to_s[0..0] == '$' if .delete(:eval_string) #puts("About to eval: #{var} = #{value}") eval("#{var} = #{value}") else marshalled_data = Marshal.dump(value) eval("#{var} = Marshal.load(%Q<#{marshalled_data}>)") end return var else raise ArgumentError.new("var must be a symbol unless :match_object => true") end end end |
#pretty_backtrace ⇒ Object
Returns a human-readable backtrace
19 20 21 22 |
# File 'lib/qualitysmith_extensions/kernel/backtrace.rb', line 19 def pretty_backtrace "Backtrace:\n" + backtrace[1..-1].map{|frame| "* " + frame}.join("\n") end |
#remove_const(const_name) ⇒ Object
This is similar to the built-in Module#remove_const
, but it is accessible from all “levels” (because it is defined in Kernel
) and can handle hierarchy.
Makes it possible to write simply:
remove_const(A::B::C.name)
rather than having to think about which module the constant is actually defined in and calling remove_const
on that module.
This is how you would otherwise have to do it:
A::B.send(:remove_const, :C)
const_name
must be an object that responds to to_s
.
const_name
must be a fully qualified name. For example, this will not work as expected:
module Mod
Foo = 'foo'
remove_const(:Foo)
end
because it will try to remove ::Foo instead of Mod::Foo. Fortunately, however, this will work as expected:
module Mod
Foo = 'foo'
remove_const(Foo.name)
end
This method is partially inspired by Facets’ Kernel#constant method, which provided a more user-friendly alternative to const_get.
47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/qualitysmith_extensions/kernel/remove_const.rb', line 47 def remove_const(const_name) #require 'pp' #puts "remove_const(#{const_name})" raise ArgumentError unless const_name.respond_to?(:to_s) nesting = const_name.to_s.split(/::/).map(&:to_sym) if nesting.size > 1 parent_module = constant(nesting[0..-2].join('::')) # For example, would be A::B for A::B::C const_to_remove = nesting[-1] # For example, would be :C for A::B::C parent_module.ignore_access.remove_const_before_was_added_to_Kernel(const_to_remove) else ignore_access.remove_const_before_was_added_to_Kernel(const_name) end end |
#remove_const! ⇒ Object
This is similar to Kernel#remove_const, but it only works for modules/classes.
This is similar to the built-in Module#remove_module
, but it lets you do it in a more object oriented manner, calling remove!
on the module/class/constant itself that you want to remove, rather than on its parent.
Makes it possible to write simply:
A::B::C.remove_const!
rather than having to think about which module the constant is actually defined in and calling remove_const
on that module. This is how you would have to otherwise do it:
A::B.send(:remove_const, :C)
27 28 29 30 31 32 33 34 35 |
# File 'lib/qualitysmith_extensions/module/remove_const.rb', line 27 def remove_const! if split.size > 1 parent_module = modspace # For example, would be A::B for A::B::C const_to_remove = split.last # For example, would be :C for A::B::C parent_module.ignore_access.remove_const(const_to_remove) else Object.ignore_access.remove_const(name) end end |
#remove_module(const) ⇒ Object
This is similar to remove_const
, but it only works for modules/classes.
This is similar to the built-in Module#remove_module
, but it is accessible from all “levels” (because it is defined in Kernel
) and can handle hierarchy.
Makes it possible to write simply:
remove_module(A::B::C)
rather than having to think about which module the constant is actually defined in and calling remove_const
on that module. This is how you would have to otherwise do it:
A::B.send(:remove_const, :C)
You can pass in either a constant or a symbol. Passing in a constant is preferred
This method is partially inspired by Facets’ Kernel#constant method, which provided a more user-friendly alternative to const_get.
32 33 34 35 36 37 38 39 40 41 |
# File 'lib/qualitysmith_extensions/kernel/remove_module.rb', line 32 def remove_module(const) const = Module.by_name(const.to_s) if const.is_a?(Symbol) if const.split.size > 1 parent_module = const.modspace # For example, would be A::B for A::B::C const_to_remove = const.split.last # For example, would be :C for A::B::C parent_module.ignore_access.remove_const(const_to_remove) else Object.ignore_access.remove_const(const.name) end end |
#require_all(what, options = {}) ⇒ Object
require
s all Ruby files specified by what
, but not matching any of the exclude filters.
-
If
what
is a string, recursivelyrequire
s all Ruby files in the directory namedwhat
or any of its subdirectories. -
If
what
is a FileList,require
s all Ruby files that match thewhat
FileList.
Options: :exclude
: An array of regular expressions or glob patterns that will be passed to FileList#exclude. If you specify this option, a file will not be included if it matches any of these patterns. :exclude_files
: An array of filenames to exclude. These will be matched exactly, so if you tell it to exclude ‘bar.rb’, ‘foobar.rb’ will not be excluded.
Examples:
require_all 'lib/', :exclude => [/ignore/, /bogus/] # will require 'lib/a.rb', 'lib/long/path/b.rb', but not 'lib/ignore/c.rb'
require_all File.dirname(__FILE__), :exclude_files => ['blow_up_stuff.rb']
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/qualitysmith_extensions/kernel/require_all.rb', line 27 def require_all(what, = {}) files, exclusions = [nil]*2 case what when String base_dir = what base_dir += '/' unless base_dir[-1].chr == '/' files = FileList[base_dir + "**/*.rb"] when FileList files = what else raise ArgumentError.new("Expected a String or a FileList") end files = files.exclude(*exclusions) if (exclusions = .delete(:exclude)) files = files.exclude(*exclusions.map {|a| File.exact_match_regexp(a) }) if (exclusions = .delete(:exclude_files)) files.each do |filename| # puts "requiring #{filename}" if filename =~ /test/ require filename end end |
#require_local_all(dir = './', options = {}) ⇒ Object
56 57 58 59 60 61 62 63 |
# File 'lib/qualitysmith_extensions/kernel/require_all.rb', line 56 def require_local_all(dir = './', = {}) raise ArgumentError.new("dir must be a String") unless dir.is_a?(String) local_dir = File.dirname( caller[0] ) require_all( File.join(local_dir, dir), ) end |
#require_once(name) ⇒ Object
Fixes bug in Ruby (1.8, at least – not sure if 2.0 fixes it) where a file can be required twice if the path is spelled differently.
12 13 14 15 16 |
# File 'lib/qualitysmith_extensions/kernel/require_once.rb', line 12 def require_once(name) raise NotImplementedError # store expand_path(name) in an array ($required_files or something) # only do the require if it wasn't already in the array end |
#trap_chain(signal_name, *args, &block) ⇒ Object
Calling Kernel#trap()
by itself will replace any previously registered handler code. Kernel#trap_chain()
, on the other hand, will add the block you supply to the existing “list” of registered handler blocks. Similar to the way Kernel#at_exit()
works, Kernel#trap_chain()
will prepend the given block
to the call chain for the given signal_name
. When the signal occurs, your block will be executed first and then the previously registered handler will be invoked. This can be called repeatedly to create a “chain” of handlers.
13 14 15 16 17 18 19 |
# File 'lib/qualitysmith_extensions/kernel/trap_chain.rb', line 13 def trap_chain(signal_name, *args, &block) previous_interrupt_handler = trap(signal_name, *args) {} trap(signal_name, *args) do block.call previous_interrupt_handler.call unless previous_interrupt_handler == "DEFAULT" end end |
#windows_platform? ⇒ Boolean
12 13 14 15 16 17 18 19 |
# File 'lib/qualitysmith_extensions/kernel/windows_platform.rb', line 12 def windows_platform? RUBY_PLATFORM =~ /mswin32/ # What about mingw32 or cygwin32? #RUBY_PLATFORM =~ /(win|w)32$/ # What about 64-bit Windows? end |