module Kernel
Public Class Methods
# File lib/utilrb/kernel/load_dsl_file.rb, line 5 def self.backtrace_remove_first_occurence_of(e, rx) # Remove the first occurence of eval_dsl_file_content in the backtrace backtrace = e.backtrace.dup found = false backtrace.delete_if do |line| break if found line =~ rx found = true end raise e, e.message, e.backtrace end
# File lib/utilrb/kernel/load_dsl_file.rb, line 153 def self.name; "" end
# File lib/utilrb/kernel/load_dsl_file.rb, line 155 def initialize(obj); @main_object = obj end
Public Instance Methods
Raises if object
can accept calls with exactly arity
arguments. object should respond to arity
# File lib/utilrb/kernel/arity.rb, line 4 def check_arity(object, arity, strict: nil) if strict.nil? if object.respond_to?(:lambda?) strict = object.lambda? else strict = true end end if strict if object.arity >= 0 && object.arity != arity raise ArgumentError, "#{object} requests #{object.arity} arguments, but #{arity} was requested" elsif -object.arity-1 > arity raise ArgumentError, "#{object} requests at least #{object.arity} arguments, but #{arity} was requested" end end end
# File lib/utilrb/kernel/load_dsl_file.rb, line 145 def dsl_exec(proxied_object, context, full_backtrace, *exceptions, &code) dsl_exec_common(nil, proxied_object, context, full_backtrace, *exceptions, &code) end
# File lib/utilrb/kernel/load_dsl_file.rb, line 149 def dsl_exec_common(file, proxied_object, context, full_backtrace, *exceptions, &code) load_dsl_filter_backtrace(file, full_backtrace, *exceptions) do sandbox = with_module(*context) do Class.new(BasicObject) do def self.name; "" end attr_accessor :main_object def initialize(obj); @main_object = obj end def method_missing(*m, &block) main_object.__send__(*m, &block) end end end old_constants, new_constants = Kernel.constants, nil sandbox = sandbox.new(proxied_object) sandbox.with_module(*context) do old_constants = if respond_to?(:constants) constants else self.class.constants end instance_eval(&code) new_constants = if respond_to?(:constants) constants else self.class.constants end end # Check if the user defined new constants by using class K and/or # mod Mod if !new_constants new_constants = Kernel.constants end new_constants -= old_constants new_constants.delete_if { |n| n.to_s == 'WithModuleConstResolutionExtension' } if !new_constants.empty? msg = "#{new_constants.first} does not exist. You cannot define new constants in this context" raise NameError.new(msg, new_constants.first) end true end end
# File lib/utilrb/kernel/load_dsl_file.rb, line 93 def eval_dsl(text, proxied_object, context, full_backtrace, *exceptions) eval_dsl_file_content(nil, text, proxied_object, context, full_backtrace, *exceptions) end
# File lib/utilrb/kernel/load_dsl_file.rb, line 86 def eval_dsl_block(block, proxied_object, context, full_backtrace, *exceptions) load_dsl_filter_backtrace(nil, full_backtrace, *exceptions) do proxied_object.with_module(*context, &block) true end end
Load the given file by eval-ing it in the provided binding. The originality of this method is to translate errors that are detected in the eval'ed code into errors that refer to the provided file
The caller of this method should call it at the end of its definition file, or the translation method may not be robust at all
# File lib/utilrb/kernel/load_dsl_file.rb, line 118 def eval_dsl_file(file, proxied_object, context, full_backtrace, *exceptions, &block) file = File.expand_path(file) if !File.readable?(file) raise ArgumentError, "#{file} does not exist" end file_content = File.read(file) eval_dsl_file_content(file, file_content, proxied_object, context, full_backtrace, *exceptions, &block) end
# File lib/utilrb/kernel/load_dsl_file.rb, line 97 def eval_dsl_file_content(file, file_content, proxied_object, context, full_backtrace, *exceptions) code = with_module(*context) do code = <<-EOD Proc.new { #{file_content} } EOD if file eval code, binding, file, 1 else eval code, binding end end dsl_exec_common(file, proxied_object, context, full_backtrace, *exceptions, &code) end
Partitions an option hash between known arguments and unknown arguments, with default value support. All option keys are converted to symbols for consistency.
The following rules apply:
* if a hash is given, non-nil values are treated as default values. * an array is equivalent to a hash where all values are 'nil'
See validate_options
and filter_and_validate_options
# File lib/utilrb/kernel/options.rb, line 32 def filter_options(options, *user_option_spec) options = options.dup known_options = Hash.new user_option_spec.each do |opt| if opt.respond_to?(:to_hash) opt.each do |key, value| if filter_options_handle_single_entry(known_options, options, key) if !value.nil? known_options[key.to_sym] = value end end end elsif opt.respond_to?(:to_ary) opt.each do |key| filter_options_handle_single_entry(known_options, options, key) end else filter_options_handle_single_entry(known_options, options, opt) end end return *[known_options, options] end
# File lib/utilrb/kernel/options.rb, line 4 def filter_options_handle_single_entry(known_options, options, key) key = key.to_sym if options.has_key?(key) known_options[key] = options.delete(key) false elsif options.has_key?(key_s = key.to_s) known_options[key] = options.delete(key_s) false else true end end
Same than eval_dsl_file
, but will not load the same file twice
# File lib/utilrb/kernel/load_dsl_file.rb, line 129 def load_dsl_file(file, *args, &block) file = File.expand_path(file) if $LOADED_FEATURES.include?(file) return false end $LOADED_FEATURES << file begin eval_dsl_file(file, *args, &block) rescue Exception $LOADED_FEATURES.delete(file) raise end true end
# File lib/utilrb/kernel/load_dsl_file.rb, line 17 def load_dsl_filter_backtrace(file, full_backtrace = false, *exceptions) # Compute the position of the dsl-loading method that called us, so that # we don't touch anything below that while we are filtering the # backtrace if !full_backtrace callers = caller our_frame_pos = caller.size callers.each do |line| if line != /load_dsl_file\.rb/ our_frame_pos -= 1 else break end end end yield rescue Exception => e raise e if full_backtrace if exceptions.any? { |e_class| e.kind_of?(e_class) } raise e end backtrace = e.backtrace.dup message = e.message.dup # Filter out the message ... it can contain backtrace information as # well (!) message = message.split("\n").map do |line| if line =~ /^.*:\d+(:.*)$/ backtrace.unshift line nil else line end end.compact.join("\n") if message.empty? message = backtrace.shift if message =~ /^(\s*[^\s]+:\d+:)\s*(.*)/ location = $1 message = $2 backtrace.unshift location else backtrace.unshift message end end filtered_backtrace = backtrace[0, backtrace.size - our_frame_pos]. map do |line| line = line.gsub(/:in `.*dsl.*'/, '') if line =~ /load_dsl_file.*(method_missing|send)/ next end if line =~ /(load_dsl_file\.rb|with_module\.rb):\d+/ next else line end end.compact backtrace = (filtered_backtrace[0, 1] + filtered_backtrace + backtrace[(backtrace.size - our_frame_pos)..-1]) raise e, message, backtrace end
# File lib/utilrb/kernel/load_dsl_file.rb, line 156 def method_missing(*m, &block) main_object.__send__(*m, &block) end
Normalizes all keys in the given option hash to symbol and returns the modified hash
# File lib/utilrb/kernel/options.rb, line 58 def normalize_options(options) options.to_sym_keys end
returns always the same null enumerator, to avoid creating objects. It can be used as a seed to inject:
enumerators.inject(null_enum) { |a, b| a + b }.each do |element| end
# File lib/utilrb/enumerable/null.rb, line 16 def null_enum @@null_enumerator ||= NullEnumerator.new.freeze end
Yields every cycle
seconds
# File lib/utilrb/kernel/poll.rb, line 3 def poll(cycle) loop do yield sleep(cycle) end end
Require all .rb files in the filename
directory
# File lib/utilrb/kernel/require.rb, line 3 def require_dir(filename, exclude = nil) dirname = filename.gsub(/.rb$/, '') Dir.new(dirname).each do |file| next if exclude && exclude === file if file =~ /\.rb$/ require File.join(dirname, file) end end end
Validates option name
in the options
hash. If required is true, raises ArgumentError if the option is not present. Otherwise, yields its value to an optional block, which should return if the value is valid, or false otherwise. If the value is invalid, raises ArgumentError with message
or a standard message.
# File lib/utilrb/kernel/options.rb, line 90 def validate_option(options, name, required, message = nil) if required && !options.has_key?(name) raise ArgumentError, "missing required option #{name}" elsif options.has_key?(name) && block_given? if !yield(options[name]) raise ArgumentError, (message || "invalid option value #{options[name]} for #{name}") end end end
Validates an option hash, with default value support. See filter_options
In the first form, option_hash
should contain keys which are also in known_hash. The non-nil values of known_hash
are used as default values. In the second form, known_array
is an array of option keys. option_hash
keys shall be in known_array
. nil
is treated as an empty option hash, all keys are converted into symbols.
# File lib/utilrb/kernel/options.rb, line 70 def validate_options(options, *known_options) options ||= Hash.new opt, unknown = Kernel.filter_options(options.to_hash, *known_options) unless unknown.empty? not_valid = unknown.keys.map { |m| "'#{m}'" }.join(" ") raise ArgumentError, "unknown options #{not_valid}", caller(1) end opt end
Yields every cycle
seconds until the block returns true.
# File lib/utilrb/kernel/poll.rb, line 11 def wait_until(cycle) until yield sleep(cycle) end end
Yields every cycle
seconds until the block returns false.
# File lib/utilrb/kernel/poll.rb, line 18 def wait_while(cycle) while yield sleep(cycle) end end
# File lib/utilrb/kernel/with_module.rb, line 18 def with_module(*consts, &block) Thread.current[:__with_module__] ||= Array.new Thread.current[:__with_module__].push consts Kernel.send(:extend, WithModuleConstResolutionExtension) Object.extend WithModuleConstResolutionExtension eval_string = if !block_given? && consts.last.respond_to?(:to_str) consts.pop end if eval_string instance_eval(eval_string) else instance_eval(&block) end ensure Thread.current[:__with_module__].pop end