Module: Kernel
- Defined in:
- lib/quality_extensions/object/default.rb,
lib/quality_extensions/kernel/die.rb,
lib/quality_extensions/range_list.rb,
lib/quality_extensions/kernel/backtrace.rb,
lib/quality_extensions/kernel/trap_chain.rb,
lib/quality_extensions/kernel/require_all.rb,
lib/quality_extensions/global_variable_set.rb,
lib/quality_extensions/kernel/remove_const.rb,
lib/quality_extensions/kernel/require_once.rb,
lib/quality_extensions/kernel/sleep_loudly.rb,
lib/quality_extensions/module/remove_const.rb,
lib/quality_extensions/kernel/remove_module.rb,
lib/quality_extensions/kernel/capture_output.rb,
lib/quality_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
-
#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.
- #RangeList(*args) ⇒ Object
-
#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.
-
#sleep_loudly(n, step = -1,, options = {}, &block) ⇒ Object
Sleeps for integer
n
number of seconds, by default counting down fromn
(inclusive) to 0, with astep
size of -1, printing the value of the counter at each step (3, 2, 1, 0 (output 4 times) ifn
is 3), each time separated by a ‘, ’. -
#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
#backtrace ⇒ Object
Equivalent to calling caller(0)
11 12 13 14 |
# File 'lib/quality_extensions/kernel/backtrace.rb', line 11 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.
23 24 25 26 27 28 29 30 |
# File 'lib/quality_extensions/kernel/backtrace.rb', line 23 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.
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 |
# File 'lib/quality_extensions/kernel/capture_output.rb', line 36 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/quality_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
11 12 13 14 |
# File 'lib/quality_extensions/kernel/die.rb', line 11 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/quality_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/quality_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/quality_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
17 18 19 20 |
# File 'lib/quality_extensions/kernel/backtrace.rb', line 17 def pretty_backtrace "Backtrace:\n" + backtrace[1..-1].map{|frame| "* " + frame}.join("\n") end |
#RangeList(*args) ⇒ Object
14 15 16 |
# File 'lib/quality_extensions/range_list.rb', line 14 def RangeList(*args) RangeList.new(*args) 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.
48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/quality_extensions/kernel/remove_const.rb', line 48 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)
28 29 30 31 32 33 34 35 36 |
# File 'lib/quality_extensions/module/remove_const.rb', line 28 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.
33 34 35 36 37 38 39 40 41 42 |
# File 'lib/quality_extensions/kernel/remove_module.rb', line 33 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']
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 |
# File 'lib/quality_extensions/kernel/require_all.rb', line 28 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 if (exclusions = .delete(:exclude)) exclusions = [exclusions] if exclusions.is_a? String files = files.exclude(*exclusions) end if (exclusions = .delete(:exclude_files)) exclusions = [exclusions] if exclusions.is_a? String files = files.exclude(*exclusions.map {|a| File.exact_match_regexp(a) }) end files.each do |filename| # puts "requiring #{filename}" if filename =~ /test/ require filename end end |
#require_local_all(dir = './', options = {}) ⇒ Object
63 64 65 66 67 68 69 70 |
# File 'lib/quality_extensions/kernel/require_all.rb', line 63 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.(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.
13 14 15 16 17 |
# File 'lib/quality_extensions/kernel/require_once.rb', line 13 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 |
#sleep_loudly(n, step = -1,, options = {}, &block) ⇒ Object
Sleeps for integer n
number of seconds, by default counting down from n
(inclusive) to 0, with a step
size of -1, printing the value of the counter at each step (3, 2, 1, 0 (output 4 times) if n
is 3), each time separated by a ‘, ’.
In effect, it is a simple on-screen countdown (or count-up) timer.
To change the step size, supply a value for step
other than -1 (the default). It will sleep for step.abs
seconds between each iteration, and at each iteration will either yield to the supplied block or (the default) output the current value of the counter).
The value of step
also determines in which direction to count: If step
is negative (the default), it counts down from n
down to 0 (inclusive). If step
is positive, it counts up from 0 up to n
(inclusive).
step
does not need to be an integer value.
If n
is not evenly divisible by step
(that is, if step * floor( / ? ) > n), the final step size will be shorter to ensure that the total amount slept is n
seconds. More precisely, the amount of time it sleeps before the final iteration (during which it won’t sleepat all) will
If a block is provided, all of the default output is overridden, and the block will be yielded with the value of the counter i once every second instead of the default behavior, allowing you to customize what gets output, if anything, or what else happens, every n.abs
seconds.
Note that it produces output (or executes your block, if supplied) n+1 times, not n times. This allows you to output (or not) both when the timer is first started and when it finishes. But because it sleeps for 1 second after the first n iterations only and not after the last, the total delay is still only n seconds.
Examples:
sleep_loudly(3)
3<sleep 1>2, <sleep 1>1, <sleep 1>0
sleep_loudly(3) {|i| puts(i == 0 ? 'Done' : i)}
3<sleep 1>
2<sleep 1>
1<sleep 1>
Done
sleep_loudly(10*60, :up, 60) {|i| print i*60, ", "} # sleep for 10 minutes, outputting after every 60 seconds
0<sleep 60>2, <sleep 60>2, <sleep 60>3,
sleep_loudly(3, :up) {|i| print i}
0<sleep 1>1<sleep 1>2<sleep 1>3
sleep_loudly(3, :up) {|i| print i+1 unless i==3}
1<sleep 1>2<sleep 1>3<sleep 1>
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 81 82 83 84 85 86 87 88 89 |
# File 'lib/quality_extensions/kernel/sleep_loudly.rb', line 41 def sleep_loudly(n, step = -1, = {}, &block) debug = [:debug] == true ? 1 : 0 #debug = 1 old_sync, STDOUT.sync = STDOUT.sync, true if step < 0 starti, endi = n, 0 elsif step > 0 starti, endi = 0, n else raise ArgumentError, "step must be positive or negative, not 0" end puts "Counting from #{starti} to #{endi} in increments of #{step} (total time should be n=#{n})" if debug i = starti final = false loop do print 'final' if final if block_given? yield *[i, final][0..block.arity-1] else print "#{i}" end break if final remaining = (i - endi).abs # if n was a multiple of step, remaining will eventually be 0, telling us that there is one final iteration to go # if n was not a multiple of step, use a different, smaller step as the final step; and we know that there is one final iteration to go if remaining < step.abs s = (step < 0 ? i-endi : endi-i) print " (using smaller final step #{s}) " if debug final = true # the next iteration is the final one else s = step end i += s print " (+#{s}=#{i}) " if debug print ", " unless block_given? print " (sleeping for #{s.abs}) " if debug sleep s.abs end print "\n" unless block_given? STDOUT.sync = old_sync 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.
15 16 17 18 19 20 21 |
# File 'lib/quality_extensions/kernel/trap_chain.rb', line 15 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/quality_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 |