rmtools 1.2.0 → 1.2.2b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Manifest.txt +3 -2
- data/README.txt +1 -1
- data/Rakefile +1 -1
- data/ext/rmtools.cpp +5 -3
- data/lib/rmtools.rb +1 -1
- data/lib/rmtools/core/arguments.rb +1 -1
- data/lib/rmtools/core/class.rb +1 -1
- data/lib/rmtools/core/kernel.rb +6 -3
- data/lib/rmtools/core/object.rb +21 -0
- data/lib/rmtools/core/threadify.rb +17 -0
- data/lib/rmtools/db/active_record.rb +27 -0
- data/lib/rmtools/dev/code_reading.rb +556 -0
- data/lib/rmtools/dev/logging.rb +6 -5
- data/lib/rmtools/dev/trace_format.rb +8 -1
- data/lib/rmtools/dev/traceback.rb +2 -1
- data/lib/rmtools/enumerable/array.rb +4 -0
- data/lib/rmtools/enumerable/array_iterators.rb +14 -3
- data/lib/rmtools/enumerable/common.rb +4 -0
- data/lib/rmtools/enumerable/range.rb +9 -1
- data/lib/rmtools/fs/dir.rb +4 -0
- data/lib/rmtools/fs/file.rb +3 -1
- data/lib/rmtools/fs/io.rb +33 -7
- data/lib/rmtools/{load.rb → init.rb} +0 -0
- data/lib/rmtools/rand/array.rb +17 -0
- data/lib/rmtools/rand/enum.rb +2 -2
- data/lib/rmtools/text/string_scanner.rb +6 -4
- data/lib/rmtools/text/string_split.rb +6 -6
- data/lib/rmtools/xml/finders.rb +21 -12
- data/lib/rmtools/xml/string.rb +7 -2
- data/lib/rmtools_dev.rb +1 -1
- metadata +15 -11
- data/lib/rmtools/dev/code_reader.rb +0 -431
    
        data/Manifest.txt
    CHANGED
    
    | @@ -17,8 +17,8 @@ lib/rmtools/dev/binding.rb | |
| 17 17 | 
             
            lib/rmtools/dev/logging.rb
         | 
| 18 18 | 
             
            lib/rmtools/dev/trace_format.rb
         | 
| 19 19 | 
             
            lib/rmtools/dev/highlight.rb
         | 
| 20 | 
            +
            lib/rmtools/dev/code_reading.rb
         | 
| 20 21 | 
             
            lib/rmtools/dev/timer.rb
         | 
| 21 | 
            -
            lib/rmtools/dev/code_reader.rb
         | 
| 22 22 | 
             
            lib/rmtools/xml/xpath.rb
         | 
| 23 23 | 
             
            lib/rmtools/xml/string.rb
         | 
| 24 24 | 
             
            lib/rmtools/xml/libxml.rb
         | 
| @@ -33,6 +33,7 @@ lib/rmtools/core/string_compliance.rb | |
| 33 33 | 
             
            lib/rmtools/core/kernel.rb
         | 
| 34 34 | 
             
            lib/rmtools/core/boolean.rb
         | 
| 35 35 | 
             
            lib/rmtools/core/aliases.rb
         | 
| 36 | 
            +
            lib/rmtools/core/threadify.rb
         | 
| 36 37 | 
             
            lib/rmtools/core/module.rb
         | 
| 37 38 | 
             
            lib/rmtools/core/object.rb
         | 
| 38 39 | 
             
            lib/rmtools/core/deprecation.rb
         | 
| @@ -66,7 +67,6 @@ lib/rmtools/fs.rb | |
| 66 67 | 
             
            lib/rmtools/ip.rb
         | 
| 67 68 | 
             
            lib/rmtools/lang.rb
         | 
| 68 69 | 
             
            lib/rmtools/functional.rb
         | 
| 69 | 
            -
            lib/rmtools/load.rb
         | 
| 70 70 | 
             
            lib/rmtools/install.rb
         | 
| 71 71 | 
             
            lib/rmtools/functional/decorate.rb
         | 
| 72 72 | 
             
            lib/rmtools/functional/fold.rb
         | 
| @@ -88,6 +88,7 @@ lib/rmtools/conversions/string.rb | |
| 88 88 | 
             
            lib/rmtools/conversions/enum.rb
         | 
| 89 89 | 
             
            lib/rmtools/conversions/int.rb
         | 
| 90 90 | 
             
            lib/rmtools/enumerable.rb
         | 
| 91 | 
            +
            lib/rmtools/init.rb
         | 
| 91 92 | 
             
            lib/rmtools/dev_min.rb
         | 
| 92 93 | 
             
            lib/rmtools_dev.rb
         | 
| 93 94 | 
             
            ./Rakefile
         | 
    
        data/README.txt
    CHANGED
    
    | @@ -14,7 +14,7 @@ Methods for basic classes addon collection. | |
| 14 14 | 
             
            * Slightly extended StringScanner
         | 
| 15 15 | 
             
            * Proof of concept: Regexp reverse (wonder if someone did it earlier in Ruby)
         | 
| 16 16 | 
             
            * Kernel#whose? to find classes and/or modules knowing some method
         | 
| 17 | 
            -
            * Method code lookup over all loaded libs (it can't handle evals yet), see dev/ | 
| 17 | 
            +
            * Method code lookup over all loaded libs (it can't handle evals yet), see dev/code_reading.rb
         | 
| 18 18 | 
             
            * Coloring is now made by singleton `Painter' and have option for transparent coloring
         | 
| 19 19 |  | 
| 20 20 | 
             
            === Version 1.1.14
         | 
    
        data/Rakefile
    CHANGED
    
    
    
        data/ext/rmtools.cpp
    CHANGED
    
    | @@ -20,15 +20,17 @@ using namespace std; | |
| 20 20 | 
             
            static VALUE object_define_new_value(VALUE self, VALUE new_obj)
         | 
| 21 21 | 
             
            {
         | 
| 22 22 | 
             
                if (FIXNUM_P(self) || self == Qnil || self == Qfalse || self == Qtrue || self == Qundef) {
         | 
| 23 | 
            -
                     | 
| 23 | 
            +
                    VALUE tmp = rb_mod_name(rb_obj_class(self));
         | 
| 24 | 
            +
                    const char* msg = StringValuePtr(tmp);
         | 
| 24 25 | 
             
                    rb_raise(rb_eTypeError, "can't redefine %s", msg);
         | 
| 25 26 | 
             
                }
         | 
| 26 27 | 
             
                if (FIXNUM_P(new_obj) || new_obj == Qnil || new_obj == Qfalse || new_obj == Qtrue  || new_obj == Qundef) {
         | 
| 27 | 
            -
                     | 
| 28 | 
            +
                    VALUE tmp = rb_mod_name(rb_obj_class(self));
         | 
| 29 | 
            +
                    const char* msg = StringValuePtr(tmp);
         | 
| 28 30 | 
             
                    rb_raise(rb_eTypeError, "can't define object as %s", msg);
         | 
| 29 31 | 
             
                }
         | 
| 30 32 | 
             
                // Place the definition of the new object in the slot of self
         | 
| 31 | 
            -
                memcpy(reinterpret_cast<void*>(self), reinterpret_cast<void*>(new_obj), SLOT_SIZE);
         | 
| 33 | 
            +
                memcpy(reinterpret_cast<void*>(self), reinterpret_cast<void*>(rb_funcall(new_obj, rb_intern("clone"), 0)), SLOT_SIZE);
         | 
| 32 34 | 
             
                return self;
         | 
| 33 35 | 
             
            }
         | 
| 34 36 |  | 
    
        data/lib/rmtools.rb
    CHANGED
    
    | @@ -1,2 +1,2 @@ | |
| 1 | 
            -
            require 'rmtools/ | 
| 1 | 
            +
            require 'rmtools/init'
         | 
| 2 2 | 
             
            RMTools::require 'dev_min'
         | 
| @@ -12,7 +12,7 @@ class Array | |
| 12 12 | 
             
                if Hash === defaults
         | 
| 13 13 | 
             
                  opts, defaults = defaults, []
         | 
| 14 14 | 
             
                  return_hash = true
         | 
| 15 | 
            -
                  $log.warn "fetch_opts(<hash>) now changed, if you want to jsut fetch hash options, use `opts = <hash>.merge(opts||{})' construction"
         | 
| 15 | 
            +
                  $log.warn "fetch_opts(<hash>) now changed, if you want to jsut fetch hash options, use `opts = <hash>.merge(opts||{})' construction", :caller => 2
         | 
| 16 16 | 
             
                else
         | 
| 17 17 | 
             
                  return_hash = false
         | 
| 18 18 | 
             
                end
         | 
    
        data/lib/rmtools/core/class.rb
    CHANGED
    
    
    
        data/lib/rmtools/core/kernel.rb
    CHANGED
    
    | @@ -3,6 +3,8 @@ module Kernel | |
| 3 3 |  | 
| 4 4 | 
             
              # re-require
         | 
| 5 5 | 
             
              def require!(file)
         | 
| 6 | 
            +
                ['.rb', '.so', '.dll', ''].each {|ext| $".delete "#{file}#{ext}"}
         | 
| 7 | 
            +
                file = File.expand_path file
         | 
| 6 8 | 
             
                ['.rb', '.so', '.dll', ''].each {|ext| $".delete "#{file}#{ext}"}
         | 
| 7 9 | 
             
                require file
         | 
| 8 10 | 
             
              end
         | 
| @@ -23,12 +25,13 @@ module Kernel | |
| 23 25 | 
             
              end
         | 
| 24 26 |  | 
| 25 27 | 
             
              def executing? file=$0
         | 
| 26 | 
            -
                caller | 
| 28 | 
            +
                caller[0] =~ /^#{file}:/
         | 
| 27 29 | 
             
              end
         | 
| 28 30 |  | 
| 29 31 | 
             
              def whose?(method, *opts)
         | 
| 30 | 
            -
                opts = opts.get_opts | 
| 31 | 
            -
                 | 
| 32 | 
            +
                opts = *opts.get_opts([:flags], :ns => :public)
         | 
| 33 | 
            +
                opts[:modules] ||= opts[:mod]
         | 
| 34 | 
            +
                checker = :"#{opts[:ns]}_method_defined?"
         | 
| 32 35 | 
             
                if Array === method
         | 
| 33 36 | 
             
                  methods = method.to_syms
         | 
| 34 37 | 
             
                else 
         | 
    
        data/lib/rmtools/core/object.rb
    CHANGED
    
    | @@ -46,6 +46,27 @@ class Object | |
| 46 46 |  | 
| 47 47 | 
             
              def in(*container)
         | 
| 48 48 | 
             
                container.size == 1 ? container[0].include?(self) : container.include?(self)
         | 
| 49 | 
            +
              end  
         | 
| 50 | 
            +
              
         | 
| 51 | 
            +
              def deep_clone
         | 
| 52 | 
            +
                _deep_clone({})
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            protected
         | 
| 56 | 
            +
              def _deep_clone(cloning_map)
         | 
| 57 | 
            +
                return cloning_map[self] if cloning_map.key? self
         | 
| 58 | 
            +
                cloning_obj = clone
         | 
| 59 | 
            +
                cloning_map[self] = cloning_obj
         | 
| 60 | 
            +
                cloning_obj.instance_variables.each do |var|
         | 
| 61 | 
            +
                  val = cloning_obj.instance_variable_get(var)
         | 
| 62 | 
            +
                  begin
         | 
| 63 | 
            +
                    val = val._deep_clone(cloning_map)
         | 
| 64 | 
            +
                  rescue TypeError
         | 
| 65 | 
            +
                    next
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
                  cloning_obj.instance_variable_set(var, val)
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
                cloning_obj
         | 
| 49 70 | 
             
              end
         | 
| 50 71 |  | 
| 51 72 | 
             
            end
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            module RMTools
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              def threadify(ary, max_threads=4)
         | 
| 4 | 
            +
                forks = []
         | 
| 5 | 
            +
                ary.each do |e|
         | 
| 6 | 
            +
                  if max_threads > forks.size
         | 
| 7 | 
            +
                    forks << fork { yield e }
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
                  if max_threads == forks.size
         | 
| 10 | 
            +
                    forks.delete Process.wait
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
                Process.waitall
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              module_function:threadify
         | 
| 17 | 
            +
            end
         | 
| @@ -76,6 +76,33 @@ module ActiveRecord | |
| 76 76 | 
             
                  find_by_sql(["SELECT * FROM #{quoted_table_name} WHERE #{primary_key} = ?", id])[0]
         | 
| 77 77 | 
             
                end
         | 
| 78 78 |  | 
| 79 | 
            +
                # values must be 2-tuple array [[column1, value1], [column2, value2], ...] and columns must be in order they've been created
         | 
| 80 | 
            +
                def self.insert_unless_exist(table, values)
         | 
| 81 | 
            +
                  table = connection.quote_table_name table
         | 
| 82 | 
            +
                  if execute_sanitized(["SELECT COUNT(*) FROM #{table} WHERE #{vaues.firsts.map {|v| "#{connection.quote_column_name v}=?"}*' AND '} LIMIT 1", *values.lasts]).to_a.flatten > 0
         | 
| 83 | 
            +
                    false
         | 
| 84 | 
            +
                  else
         | 
| 85 | 
            +
                    execute_sanitized ["INSERT INTO #{table} VALUES (#{['?']*values.size*','})", *values.lasts]
         | 
| 86 | 
            +
                    true
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
                
         | 
| 90 | 
            +
                def resource_path
         | 
| 91 | 
            +
                  "#{self.class.name.tableize}/#{id}"
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
                
         | 
| 94 | 
            +
              end
         | 
| 95 | 
            +
              
         | 
| 96 | 
            +
              class Relation
         | 
| 97 | 
            +
                
         | 
| 98 | 
            +
                def any?
         | 
| 99 | 
            +
                  limit(1).count != 0
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
                
         | 
| 102 | 
            +
                def empty?
         | 
| 103 | 
            +
                  limit(1).count == 0
         | 
| 104 | 
            +
                end
         | 
| 105 | 
            +
                
         | 
| 79 106 | 
             
              end
         | 
| 80 107 |  | 
| 81 108 | 
             
            end
         | 
| @@ -0,0 +1,556 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
            RMTools::require 'text/string_scanner'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module RMTools
         | 
| 5 | 
            +
              class CodeReader
         | 
| 6 | 
            +
                attr_reader :MethodCache, :stack
         | 
| 7 | 
            +
                
         | 
| 8 | 
            +
                module Defaults
         | 
| 9 | 
            +
                  Leftop = leftop = '\[{(<=>~+\-*,;:^&\|'
         | 
| 10 | 
            +
                  rightop = '\])}?!'
         | 
| 11 | 
            +
                  sname = '\w<=>~+\-*/\]\[\^%!?@&\|'
         | 
| 12 | 
            +
                  compname = "([\\.:#{sname}]+)"
         | 
| 13 | 
            +
                  name = "([#{sname}]+)"
         | 
| 14 | 
            +
                  mname = '([:\w]+)'
         | 
| 15 | 
            +
                  call_ = '(\{s*\||([\w][?!]?|\)|\.((\[\]|[<=>])?=[=~]?|[<>*\-+/%^&\|]+))[ \t]*\{)'
         | 
| 16 | 
            +
                  space = '[ \t]+'
         | 
| 17 | 
            +
                  space_ = '[ \t]*'
         | 
| 18 | 
            +
                  kw = 'if|elsif|else|unless|while|until|case|begin|rescue|when|then|or|and|not'
         | 
| 19 | 
            +
                  heredoc_handle = %q{<<(-)?(\w+|`[^`]+`|'[^']+'|"[^"]+")}
         | 
| 20 | 
            +
                  heredoc = %{([\\s#{leftop}?]|[#{leftop}\\w!?][ \t])\\s*#{heredoc_handle}}
         | 
| 21 | 
            +
                  re_sugar = %{(^|[#{leftop}\\n?;]|\W!|\\b(#{kw})[ \t]|[\\w#{rightop}]/)\\s*/}
         | 
| 22 | 
            +
                  percent = '%([xwqrQW])?([\\/<({\[!\|])'
         | 
| 23 | 
            +
                  simple = [re_sugar, percent, '[#\'"`]']*'|'
         | 
| 24 | 
            +
                  mod_def = "module +#{mname}"
         | 
| 25 | 
            +
                  class_def = "class(?: *(<<) *| +)([$@:\\w]+)(?: *< *#{mname})?"
         | 
| 26 | 
            +
                  method_def = "def +#{compname}"
         | 
| 27 | 
            +
                  alias_def = "alias +:?#{name} +:?#{name}"
         | 
| 28 | 
            +
                  Ender = '\s*\)? *(?:end\b|[\n;})\]])'
         | 
| 29 | 
            +
                  
         | 
| 30 | 
            +
                  StringParseRE = /#{heredoc}|#{simple}|[{}]|[^\w#{rightop}'"`\/\\]\?\\?\S/m
         | 
| 31 | 
            +
                  HeredocParseRE = /\n|#{heredoc}|#{simple}/m
         | 
| 32 | 
            +
                  ArgumentsParseRE = /#{simple}|[{}()\[\]\n;,\|]| end\b|[:@$.\w!?]+(\b|[( ] *)| +[:?]\s+| *=>\s*/m
         | 
| 33 | 
            +
                  
         | 
| 34 | 
            +
                  StringRE = /(^['"`]$)|^#{percent}$/
         | 
| 35 | 
            +
                  RERE = %r{(?:^|[#{leftop}\w!\s/])\s*(/)}
         | 
| 36 | 
            +
                  HeredocRE = heredoc_handle.to_re
         | 
| 37 | 
            +
                  Symbol = /^:#{name}$/
         | 
| 38 | 
            +
                  Attrs = /\s(c)?(?:attr_(reader|writer|accessor))[( ] *((?::\w+ *,\s*)*:\w+)#{Ender}/
         | 
| 39 | 
            +
                  Include = /\s(include|extend) +#{mname}/
         | 
| 40 | 
            +
                  AliasMethod = /\salias_method :#{name} *,\s*:#{name}/
         | 
| 41 | 
            +
                  Beginners = /(([#{leftop}\n]?\s*)(if|unless|while|until))#{
         | 
| 42 | 
            +
                    }|(.)?(?:(do|for)|begin|case)/
         | 
| 43 | 
            +
                  EOF = /($0\s*==\s*__FILE__\s*|__FILE__\s*==\s*\$0\s*)?\n/
         | 
| 44 | 
            +
                  BlockOpen = /(?:^\{\s*\||.\{)$/
         | 
| 45 | 
            +
                  Ord = /^\W\?\\?\S$/
         | 
| 46 | 
            +
                  
         | 
| 47 | 
            +
                  MainParseRE = /#{simple
         | 
| 48 | 
            +
                    }|#{call_}|[{}]#{
         | 
| 49 | 
            +
                    }|(^|\n)=begin\b#{
         | 
| 50 | 
            +
                    }|^\s*[;\(]? *(#{mod_def}|#{method_def})#{
         | 
| 51 | 
            +
                    }|:#{name}#{
         | 
| 52 | 
            +
                    }|[^\w#{rightop}'"`\/\\]\?\\?\S#{
         | 
| 53 | 
            +
                    }|#{heredoc
         | 
| 54 | 
            +
                    }|(^|[#{leftop}\n])\s*((if|unless)\b|#{
         | 
| 55 | 
            +
                                                                }[;\(]? *#{class_def})#{
         | 
| 56 | 
            +
                    }|(^|[\n;])\s*(while|until)\b#{
         | 
| 57 | 
            +
                    }|(^|[#{leftop}\s?])(do|case|begin|for)\b#{
         | 
| 58 | 
            +
                    }\s(c)?(?:attr_(reader|writer|accessor))[( ] *((?::\w+ *,\s*)*:\w+)#{Ender
         | 
| 59 | 
            +
                    }|\salias_method +:#{name} *,\s*:#{name
         | 
| 60 | 
            +
                    }|\s(include|extend)[( ] *#{mname
         | 
| 61 | 
            +
                    }|(^|[;\s])(#{alias_def}|end|__END__)\b/m
         | 
| 62 | 
            +
                    
         | 
| 63 | 
            +
                  ModDef = mod_def.to_re
         | 
| 64 | 
            +
                  ClassDef = class_def.to_re
         | 
| 65 | 
            +
                  MethodDef = method_def.to_re
         | 
| 66 | 
            +
                  AliasDef = alias_def.to_re
         | 
| 67 | 
            +
                  
         | 
| 68 | 
            +
                  def self::Class(s, m)       
         | 
| 69 | 
            +
                    debug
         | 
| 70 | 
            +
                    _stack = clean_stack
         | 
| 71 | 
            +
                    if _stack[-1] == [:block]
         | 
| 72 | 
            +
                        stack << [:beginner]
         | 
| 73 | 
            +
                    elsif m[1]
         | 
| 74 | 
            +
                        if m[2] =~ /^[@$]/
         | 
| 75 | 
            +
                            stack << [:beginner]
         | 
| 76 | 
            +
                        elsif _stack.any? and _stack[-1][0] == :def
         | 
| 77 | 
            +
                            stack << [:beginner]
         | 
| 78 | 
            +
                        else
         | 
| 79 | 
            +
                            slf = _stack.lasts*'::'
         | 
| 80 | 
            +
                            name = m[2].sub 'self.', ''
         | 
| 81 | 
            +
                            name.sub! 'self', slf
         | 
| 82 | 
            +
                            name = fix_module_name slf, name
         | 
| 83 | 
            +
                            stack << [:singleton, name]
         | 
| 84 | 
            +
                        end
         | 
| 85 | 
            +
                    else
         | 
| 86 | 
            +
                        new = clean_stack.lasts*'::'
         | 
| 87 | 
            +
                        stack << [:class, m[2]]
         | 
| 88 | 
            +
                        name = fix_module_name new, m[3] if m[3]
         | 
| 89 | 
            +
                        new << '::' if new.b
         | 
| 90 | 
            +
                        new << m[2]
         | 
| 91 | 
            +
                        MethodCache[new] ||= {}
         | 
| 92 | 
            +
                        inherit! new, name if m[3]
         | 
| 93 | 
            +
                    end
         | 
| 94 | 
            +
                  end
         | 
| 95 | 
            +
                  
         | 
| 96 | 
            +
                  def self::Module(s, m)
         | 
| 97 | 
            +
                    debug
         | 
| 98 | 
            +
                    stack << [:mod, m[1]]
         | 
| 99 | 
            +
                    MethodCache[clean_stack.lasts*'::'] = {}
         | 
| 100 | 
            +
                  end
         | 
| 101 | 
            +
                  
         | 
| 102 | 
            +
                  def self::Method(s, m)
         | 
| 103 | 
            +
                    debug
         | 
| 104 | 
            +
                    _stack = clean_stack(true)
         | 
| 105 | 
            +
                    if _stack[-1] == [:block]
         | 
| 106 | 
            +
                        stack << [:beginner]
         | 
| 107 | 
            +
                    end
         | 
| 108 | 
            +
                    start = s.pos - s.matched[/[^\n]+$/].size
         | 
| 109 | 
            +
                    name = m[1].sub(/::([^:.]+)$/, '.\1')
         | 
| 110 | 
            +
                    name.sub!(/#{_stack.last[1]}\./, 'self.') if _stack.any?
         | 
| 111 | 
            +
                    if name[/^self\.(.+)/]
         | 
| 112 | 
            +
                        stack << [:def, "#{_stack.lasts*'::'}.#$1", start]
         | 
| 113 | 
            +
                    elsif name['.'] and name =~ /^[A-Z]/
         | 
| 114 | 
            +
                        mod, name = name/'.'
         | 
| 115 | 
            +
                        fix_module_name(_stack.lasts*'::', mod) >> '.' >> name
         | 
| 116 | 
            +
                        stack << [:def, name, start]
         | 
| 117 | 
            +
                    else
         | 
| 118 | 
            +
                        prefix = (_stack.any? && _stack[-1][0] == :singleton) ? _stack[-1][1]+'.' : _stack.lasts*'::'+'#'
         | 
| 119 | 
            +
                        stack << [:def, prefix+name, start]
         | 
| 120 | 
            +
                    end
         | 
| 121 | 
            +
                  end
         | 
| 122 | 
            +
                  
         | 
| 123 | 
            +
                  def self::Alias(s, m)
         | 
| 124 | 
            +
                    debug
         | 
| 125 | 
            +
                    _stack = clean_stack
         | 
| 126 | 
            +
                    case _stack.any? && _stack[-1][0]
         | 
| 127 | 
            +
                      when false, :def, :block
         | 
| 128 | 
            +
                          return
         | 
| 129 | 
            +
                      when :singleton
         | 
| 130 | 
            +
                          prefix = _stack[-1][1]
         | 
| 131 | 
            +
                          new, old = '.'+m[1], '.'+m[2]
         | 
| 132 | 
            +
                      else
         | 
| 133 | 
            +
                          prefix = _stack.lasts*'::'
         | 
| 134 | 
            +
                          new, old = '#'+m[1], '#'+m[2]
         | 
| 135 | 
            +
                    end
         | 
| 136 | 
            +
                    MethodCache[prefix][new] = MethodCache[prefix][old] || "def #{new}(*args)\n  #{old}(*args)\nend"
         | 
| 137 | 
            +
                  end
         | 
| 138 | 
            +
                  
         | 
| 139 | 
            +
                end if !defined? Defaults
         | 
| 140 | 
            +
                  
         | 
| 141 | 
            +
                Closers = {'<' => '>', '{' => '}', '[' => ']', '(' => ')'}
         | 
| 142 | 
            +
                
         | 
| 143 | 
            +
                def init_instructions
         | 
| 144 | 
            +
                  [
         | 
| 145 | 
            +
                      [/^\#/, lambda {|s, m| s.scan_until(/\n/)}],
         | 
| 146 | 
            +
                      [@Processor::StringRE, method(:string)],
         | 
| 147 | 
            +
                      
         | 
| 148 | 
            +
                      [/^\{$/, lambda {|s, m| 
         | 
| 149 | 
            +
                        debug
         | 
| 150 | 
            +
                        $log.debug @curls_count
         | 
| 151 | 
            +
                        @curls_count += 1
         | 
| 152 | 
            +
                      }],
         | 
| 153 | 
            +
                      
         | 
| 154 | 
            +
                      [/^\}$/, method(:curl_close)],
         | 
| 155 | 
            +
                      [@Processor::Ord],
         | 
| 156 | 
            +
                      
         | 
| 157 | 
            +
                      [@Processor::BlockOpen, lambda {|s, m| 
         | 
| 158 | 
            +
                        debug
         | 
| 159 | 
            +
                        $log.debug @curls_count
         | 
| 160 | 
            +
                        @stack << [:block]
         | 
| 161 | 
            +
                      }],
         | 
| 162 | 
            +
                      
         | 
| 163 | 
            +
                      [@Processor::ModDef, @Processor.method(:Module)],
         | 
| 164 | 
            +
                      [@Processor::ClassDef, @Processor.method(:Class)],
         | 
| 165 | 
            +
                      [@Processor::MethodDef, @Processor.method(:Method)],
         | 
| 166 | 
            +
                      [@Processor::AliasDef, @Processor.method(:Alias)],
         | 
| 167 | 
            +
                      [@Processor::Symbol],
         | 
| 168 | 
            +
                      [@Processor::RERE, method(:string)],
         | 
| 169 | 
            +
                      [@Processor::HeredocRE, method(:heredoc)],
         | 
| 170 | 
            +
                      
         | 
| 171 | 
            +
                      [/(^|\n)=begin/, lambda {|s, m| s.scan_until(/\n=end\s*\n/m)}],
         | 
| 172 | 
            +
                      
         | 
| 173 | 
            +
                      [@Processor::Attrs, lambda {|s, m|
         | 
| 174 | 
            +
                        attr_accessors s, m
         | 
| 175 | 
            +
                        if s.matched =~ / end$/
         | 
| 176 | 
            +
                          end!(s)
         | 
| 177 | 
            +
                        elsif s.matched =~ /[^\?]}$/
         | 
| 178 | 
            +
                          curl_close
         | 
| 179 | 
            +
                        end
         | 
| 180 | 
            +
                      }],
         | 
| 181 | 
            +
                      
         | 
| 182 | 
            +
                      [@Processor::Include, lambda {|s, m|
         | 
| 183 | 
            +
                        _stack = clean_stack
         | 
| 184 | 
            +
                        if _stack.empty?
         | 
| 185 | 
            +
                          if m[1] == 'include'
         | 
| 186 | 
            +
                            inherit! 'Object', m[2] 
         | 
| 187 | 
            +
                          else
         | 
| 188 | 
            +
                            inherit_singletons! 'Object', m[2] 
         | 
| 189 | 
            +
                          end
         | 
| 190 | 
            +
                        elsif !_stack[-1][0].in([:def, :block]) and m[2] =~ /^[A-Z]/
         | 
| 191 | 
            +
                          if m[1] == 'include'
         | 
| 192 | 
            +
                            inherit! _stack.lasts*'::', m[2] 
         | 
| 193 | 
            +
                          else
         | 
| 194 | 
            +
                            inherit_singletons! _stack.lasts*'::', m[2] 
         | 
| 195 | 
            +
                          end
         | 
| 196 | 
            +
                        end
         | 
| 197 | 
            +
                      }],
         | 
| 198 | 
            +
                      
         | 
| 199 | 
            +
                      [@Processor::AliasMethod, lambda {|s, m|
         | 
| 200 | 
            +
                        _stack = clean_stack
         | 
| 201 | 
            +
                        if _stack[-1][0] == :class
         | 
| 202 | 
            +
                          new, old = m[1..2]
         | 
| 203 | 
            +
                          prefix = _stack.lasts*'::'
         | 
| 204 | 
            +
                          @MethodCache[prefix][new] = @MethodCache[prefix][old] || "def #{new}(*args)\n  #{old}(*args)\nend"
         | 
| 205 | 
            +
                        end
         | 
| 206 | 
            +
                      }],
         | 
| 207 | 
            +
                      
         | 
| 208 | 
            +
                      [@Processor::Beginners, lambda {|s, m|
         | 
| 209 | 
            +
                        debug
         | 
| 210 | 
            +
                        $log.debug [m, s.last, s.string[s.last-1,1].to_s]
         | 
| 211 | 
            +
                        if (m[2] and s.last != 0 and m[2].tr(' \t', '').empty? and !(s.string[s.last-1,1].to_s)[/[\n;({\[]/])
         | 
| 212 | 
            +
                        else
         | 
| 213 | 
            +
                          if m[3] == 'if' and @stack.empty? and s.check_until(@Processor::EOF) and s.matched != "\n"
         | 
| 214 | 
            +
                            throw :EOF
         | 
| 215 | 
            +
                          end
         | 
| 216 | 
            +
                          @stack << [m[5] ? :block : :beginner]
         | 
| 217 | 
            +
                        end
         | 
| 218 | 
            +
                      }],
         | 
| 219 | 
            +
                      
         | 
| 220 | 
            +
                      [/(^|[\s;])end.?/, method(:end!)],
         | 
| 221 | 
            +
                      [/(^|[\s;])__END__/, lambda {|s, m| throw :EOF}]
         | 
| 222 | 
            +
                  ].dup
         | 
| 223 | 
            +
                end
         | 
| 224 | 
            +
                  
         | 
| 225 | 
            +
                def debug(s,m)
         | 
| 226 | 
            +
                  $log.debug(:caller=>2) {"#{s.string[0, s.pos].count("\n")+1}:#{s.head.size + s.matched_size - ((s.head+s.matched).reverse.index("\n") || 0)}"}
         | 
| 227 | 
            +
                  $log.debug(@stack, :caller=>2)
         | 
| 228 | 
            +
                  $log.debug(:caller=>2) {Painter.g(s.head+s.matched)}
         | 
| 229 | 
            +
                end
         | 
| 230 | 
            +
                
         | 
| 231 | 
            +
                def initialize(instructions_module=Defaults)
         | 
| 232 | 
            +
                  @MethodCache = {'Object' => {}}
         | 
| 233 | 
            +
                  @ReadPaths = {}
         | 
| 234 | 
            +
                  @Processor = instructions_module
         | 
| 235 | 
            +
                  @Instructions = init_instructions
         | 
| 236 | 
            +
                  @MainParseRE = @Processor::MainParseRE
         | 
| 237 | 
            +
                  add_method_seeker('get_opts') {|s, args| $log << args}
         | 
| 238 | 
            +
                end
         | 
| 239 | 
            +
                
         | 
| 240 | 
            +
                def add_instruction(re, &callback)
         | 
| 241 | 
            +
                  @MainParseRE |= re 
         | 
| 242 | 
            +
                  @Instructions << [re, callback]
         | 
| 243 | 
            +
                end
         | 
| 244 | 
            +
                
         | 
| 245 | 
            +
                def add_method_seeker(name, *args, &callback)
         | 
| 246 | 
            +
                  pattern = /(?:^|[\s#{@Processor::Leftop}])(#{name})[( ] */
         | 
| 247 | 
            +
                  add_instruction(pattern) {|s, m|
         | 
| 248 | 
            +
                    yield s, arguments(s, m)
         | 
| 249 | 
            +
                  }
         | 
| 250 | 
            +
                end
         | 
| 251 | 
            +
                
         | 
| 252 | 
            +
                # Parser methods
         | 
| 253 | 
            +
                
         | 
| 254 | 
            +
                def arguments(s, m)
         | 
| 255 | 
            +
                  arg_list = [m[1]]
         | 
| 256 | 
            +
                  counts = {'}' => 0, ']' => 0, ')' => 0}
         | 
| 257 | 
            +
                  catch(:EOL) {s.each(@Processor::ArgumentsParseRE, [
         | 
| 258 | 
            +
                      [/^[{\[(]$/, lambda {|s, m| counts[Closers[m[0]]] += 1}],
         | 
| 259 | 
            +
                      [/^[}\])]$/, lambda {|s, m| 
         | 
| 260 | 
            +
                        if counts[m[0]] > 0
         | 
| 261 | 
            +
                          counts[m[0]] -= 1
         | 
| 262 | 
            +
                        else
         | 
| 263 | 
            +
                          curl_close
         | 
| 264 | 
            +
                          throw :EOL
         | 
| 265 | 
            +
                        end
         | 
| 266 | 
            +
                      }],
         | 
| 267 | 
            +
                      [/^[,\|]$/, lambda {|s, m| s.scan_until(/\s*/m)}],
         | 
| 268 | 
            +
                      [/[#\n;]| end\b/, lambda {|s, m| 
         | 
| 269 | 
            +
                        s.scan_until(/\n/) if m[0] == '#'
         | 
| 270 | 
            +
                        heredoc_list.each {|opener| string(s, [nil]*4+opener)}
         | 
| 271 | 
            +
                        throw :EOL
         | 
| 272 | 
            +
                      }],
         | 
| 273 | 
            +
                      [@Processor::StringRE, lambda {|s, m| 
         | 
| 274 | 
            +
                        str = [s.pos-1, string(s, m)]
         | 
| 275 | 
            +
                        str[1] ? arg_list << s.string[str[0]...str[1]] : arg_list << s.string[str[0]-1..str[0]]
         | 
| 276 | 
            +
                      }],
         | 
| 277 | 
            +
                      [@Processor::RERE, lambda {|s, m| 
         | 
| 278 | 
            +
                        str = [s.pos-1, string(s, m)]
         | 
| 279 | 
            +
                        arg_list << s.string[str[0]...str[1]]
         | 
| 280 | 
            +
                      }],
         | 
| 281 | 
            +
                      [/^ +[:?]\s+$/],
         | 
| 282 | 
            +
                      [/^ *=>\s*$/, lambda {|s, m| arg_list << '=>'}],
         | 
| 283 | 
            +
                      [/^[:@$.\w!?]+([( ] *)?$/, lambda {|s, m| 
         | 
| 284 | 
            +
                        str = [s.pos-s.matched_size, arguments(s, m) && s.pos]
         | 
| 285 | 
            +
                        arg_list << s.string[str[0]...str[1]] if str[1]
         | 
| 286 | 
            +
                      }]
         | 
| 287 | 
            +
                  ])}
         | 
| 288 | 
            +
                  arg_list
         | 
| 289 | 
            +
                end
         | 
| 290 | 
            +
                
         | 
| 291 | 
            +
                def string(s, m)
         | 
| 292 | 
            +
                  debug
         | 
| 293 | 
            +
                  return if m[1] and s.- == '$'
         | 
| 294 | 
            +
                  opener = m[1] || m[3] || m[5]
         | 
| 295 | 
            +
                  $log.log {"entering #{opener}-quotes, matched as '#{Painter.g s.matched}' at #{s.string[0..s.pos].count("\n")+1}"}
         | 
| 296 | 
            +
                  if opener == m[5]
         | 
| 297 | 
            +
                    closer = opener = m[5].tr('`\'"', '')
         | 
| 298 | 
            +
                    quote_re = /\\|\n#{'\s*' if m[4]}#{closer}/
         | 
| 299 | 
            +
                  else
         | 
| 300 | 
            +
                    closer = Closers[opener] || opener
         | 
| 301 | 
            +
                    quote_re = /\\|#{Regexp.escape closer}/
         | 
| 302 | 
            +
                  end
         | 
| 303 | 
            +
                  openers_cnt = 1
         | 
| 304 | 
            +
                  inner_curls_count = 0
         | 
| 305 | 
            +
                  backslash = false
         | 
| 306 | 
            +
                  quote_re |= /#\{/ if (m[5] and m[5].ord != ?') or closer =~ /[\/"`]/ or (m[2] =~ /[xrQW]/ or m[3])
         | 
| 307 | 
            +
                  instructions = [
         | 
| 308 | 
            +
                    [@Processor::Ord],
         | 
| 309 | 
            +
                    [/\s*#{Regexp.escape closer}$/, lambda {|s, m|
         | 
| 310 | 
            +
                      if backslash
         | 
| 311 | 
            +
                        backslash = false
         | 
| 312 | 
            +
                        break if s.- == '\\' and m[0] == closer
         | 
| 313 | 
            +
                      end
         | 
| 314 | 
            +
                      if (openers_cnt -= 1) == 0
         | 
| 315 | 
            +
                        $log.log {"exiting through #{closer}-quotes at #{s.string[0...s.pos].count("\n")+1}"}
         | 
| 316 | 
            +
                        throw :EOS 
         | 
| 317 | 
            +
                    else
         | 
| 318 | 
            +
                        $log.log 'decreasing openers count'
         | 
| 319 | 
            +
                      end
         | 
| 320 | 
            +
                    }],
         | 
| 321 | 
            +
                    [/\\/, lambda {|s, m|
         | 
| 322 | 
            +
                      prev = s.-
         | 
| 323 | 
            +
                      backslash = true
         | 
| 324 | 
            +
                      if prev == '\\'
         | 
| 325 | 
            +
                        i = 2
         | 
| 326 | 
            +
                        while prev == '\\'
         | 
| 327 | 
            +
                          prev = s.prev_in i
         | 
| 328 | 
            +
                          i += 1
         | 
| 329 | 
            +
                          backslash = !backslash
         | 
| 330 | 
            +
                        end
         | 
| 331 | 
            +
                      end
         | 
| 332 | 
            +
                    $log.log {"#{!backslash ? 'closed' : 'found'} \\ in #{opener}-quotes at #{s.string[0, s.pos].count("\n")+1}"}
         | 
| 333 | 
            +
                    }],
         | 
| 334 | 
            +
                    [/\#\{/, lambda {|s, m| 
         | 
| 335 | 
            +
                      if backslash
         | 
| 336 | 
            +
                        backslash = false
         | 
| 337 | 
            +
                        if s.- == '\\'
         | 
| 338 | 
            +
                          openers_cnt += 1 if closer == '}'
         | 
| 339 | 
            +
                          break
         | 
| 340 | 
            +
                        end
         | 
| 341 | 
            +
                      end
         | 
| 342 | 
            +
                    $log.log "entering curls"
         | 
| 343 | 
            +
                      inner_curls_count += 1
         | 
| 344 | 
            +
                      catch(:inner_out) {s.each(@Processor::StringParseRE, [
         | 
| 345 | 
            +
                          [/^\#$/, lambda {|s, m| 
         | 
| 346 | 
            +
                          $log.log 'reading comment'
         | 
| 347 | 
            +
                         s.scan_until(/\n/)}],
         | 
| 348 | 
            +
                          [/^\{$/, lambda {|s, m| 
         | 
| 349 | 
            +
                          $log.log "increasing curls count"
         | 
| 350 | 
            +
                          inner_curls_count += 1}],
         | 
| 351 | 
            +
                          [/^\}$/, lambda {|s, m| 
         | 
| 352 | 
            +
                          if (inner_curls_count -= 1) == 0
         | 
| 353 | 
            +
                            $log.log "exiting curls"
         | 
| 354 | 
            +
                            throw :inner_out
         | 
| 355 | 
            +
                          else
         | 
| 356 | 
            +
                            $log.log "decreasing curls count"
         | 
| 357 | 
            +
                          end}],
         | 
| 358 | 
            +
                          [@Processor::HeredocRE, method(:heredoc)],
         | 
| 359 | 
            +
                          [@Processor::StringRE, method(:string)],
         | 
| 360 | 
            +
                          [@Processor::RERE, method(:string)]
         | 
| 361 | 
            +
                      ])}
         | 
| 362 | 
            +
                    }]
         | 
| 363 | 
            +
                  ]
         | 
| 364 | 
            +
                  if closer != opener
         | 
| 365 | 
            +
                    quote_re |= /#{Regexp.escape opener}/
         | 
| 366 | 
            +
                    instructions << [/#{Regexp.escape opener}$/, lambda {|s, m|
         | 
| 367 | 
            +
                      if backslash
         | 
| 368 | 
            +
                        backslash = false
         | 
| 369 | 
            +
                        break if s.- == '\\'
         | 
| 370 | 
            +
                      end
         | 
| 371 | 
            +
                    $log.log 'increasing openers count'
         | 
| 372 | 
            +
                      openers_cnt += 1
         | 
| 373 | 
            +
                    }]
         | 
| 374 | 
            +
                    $log.debug [quote_re,instructions]
         | 
| 375 | 
            +
                  end
         | 
| 376 | 
            +
                    
         | 
| 377 | 
            +
                  catch(:EOS) {s.each(quote_re, instructions)}
         | 
| 378 | 
            +
                  s.pos
         | 
| 379 | 
            +
                end
         | 
| 380 | 
            +
                
         | 
| 381 | 
            +
                def heredoc(s=nil, m)
         | 
| 382 | 
            +
                  heredoc_list = [m[1..2]]
         | 
| 383 | 
            +
                  catch(:EOL) {s.each(@Processor::HeredocParseRE, [
         | 
| 384 | 
            +
                      [/[#\n]/, lambda {|s, m| 
         | 
| 385 | 
            +
                        s.scan_until(/\n/) if m[0] == '#'
         | 
| 386 | 
            +
                        heredoc_list.each {|opener| string(s, [nil]*4+opener)}
         | 
| 387 | 
            +
                        throw :EOL
         | 
| 388 | 
            +
                      }],
         | 
| 389 | 
            +
                      [@Processor::HeredocRE, lambda {|s, m| heredoc_list << m[1..2]}],
         | 
| 390 | 
            +
                      [@Processor::StringRE, method(:string)],
         | 
| 391 | 
            +
                      [@Processor::RERE, method(:string)]
         | 
| 392 | 
            +
                  ])}
         | 
| 393 | 
            +
                end
         | 
| 394 | 
            +
                
         | 
| 395 | 
            +
                def curl_close(*)
         | 
| 396 | 
            +
                  if @curls_count == 0
         | 
| 397 | 
            +
                    @stack.pop
         | 
| 398 | 
            +
                  else
         | 
| 399 | 
            +
                    @curls_count -= 1
         | 
| 400 | 
            +
                  end
         | 
| 401 | 
            +
                end
         | 
| 402 | 
            +
                
         | 
| 403 | 
            +
                def end!(s, *)
         | 
| 404 | 
            +
                  debug
         | 
| 405 | 
            +
                  if s.+ !~ /[?!(]/
         | 
| 406 | 
            +
                    exit = @stack.pop
         | 
| 407 | 
            +
                    case exit[0]
         | 
| 408 | 
            +
                      when :def
         | 
| 409 | 
            +
                        prefix, name = exit[1].sharp_split(/[.@#]/, 2)
         | 
| 410 | 
            +
                        if !name
         | 
| 411 | 
            +
                          prefix, name = 'Object', prefix
         | 
| 412 | 
            +
                        end
         | 
| 413 | 
            +
                        if @MethodCache[prefix]
         | 
| 414 | 
            +
                          (@MethodCache[prefix][name] ||= []) << (path.inline ? [path, exit[2]...s.pos] : s.string[exit[2]...s.pos])
         | 
| 415 | 
            +
                        end
         | 
| 416 | 
            +
                    end
         | 
| 417 | 
            +
                  end
         | 
| 418 | 
            +
                end
         | 
| 419 | 
            +
                
         | 
| 420 | 
            +
                def attr_accessors(s, m)
         | 
| 421 | 
            +
                  _stack = clean_stack
         | 
| 422 | 
            +
                  if _stack[-1][0] == :class
         | 
| 423 | 
            +
                    prefix = _stack.lasts*'::'
         | 
| 424 | 
            +
                    attrs = (m[3]/',').map {|attr| (m[1] ? '.' : '#')+attr.strip[1..-1]}
         | 
| 425 | 
            +
                    if m[2].in %w(reader accessor)
         | 
| 426 | 
            +
                      attrs.each {|attr| (@MethodCache[prefix][attr] ||= []) << "def #{'self.' if m[1]}#{attr}\n  #{'@' if m[1]}@#{attr}\nend"}
         | 
| 427 | 
            +
                    end
         | 
| 428 | 
            +
                    if m[2].in %w(writer accessor)
         | 
| 429 | 
            +
                      attrs.each {|attr| (@MethodCache[prefix][attr] ||= []) << "def #{'self.' if m[1]}#{attr}=value\n  #{'@' if m[1]}@#{attr} = value\nend"}
         | 
| 430 | 
            +
                    end
         | 
| 431 | 
            +
                  end
         | 
| 432 | 
            +
                end
         | 
| 433 | 
            +
             | 
| 434 | 
            +
                def parse_file(path)
         | 
| 435 | 
            +
                  @stack = []
         | 
| 436 | 
            +
                  
         | 
| 437 | 
            +
                  if path.inline
         | 
| 438 | 
            +
                    return if @ReadPaths[path]
         | 
| 439 | 
            +
                    lines = get_lines(path)[0]
         | 
| 440 | 
            +
                    @ReadPaths[path] = true
         | 
| 441 | 
            +
                  else
         | 
| 442 | 
            +
                    lines = path.sharp_split(/\n/)
         | 
| 443 | 
            +
                  end
         | 
| 444 | 
            +
                  if RUBY_VERSION > '1.9'
         | 
| 445 | 
            +
                    ss = StringScanner lines.join.force_encoding('UTF-8')
         | 
| 446 | 
            +
                  else
         | 
| 447 | 
            +
                    ss = StringScanner lines.join
         | 
| 448 | 
            +
                  end
         | 
| 449 | 
            +
                  
         | 
| 450 | 
            +
                  @curls_count = 0
         | 
| 451 | 
            +
                  catch(:EOF) { ss.each @MainParseRE, @Instructions }
         | 
| 452 | 
            +
                  raise "Can't parse: #{@stack.inspect}, #{ss.string[ss.last..ss.pos].inspect}" if @stack.any?
         | 
| 453 | 
            +
                  ss
         | 
| 454 | 
            +
                end
         | 
| 455 | 
            +
             | 
| 456 | 
            +
                def clean_stack(no_def=false)
         | 
| 457 | 
            +
                  @stack.select {|e| e[0] != :beginner and !no_def || e[0] != :def}
         | 
| 458 | 
            +
                end
         | 
| 459 | 
            +
             | 
| 460 | 
            +
                def inherit!(descendant, ancestor)
         | 
| 461 | 
            +
                  @MethodCache[descendant].reverse_merge((
         | 
| 462 | 
            +
                    @MethodCache[fix_module_name(descendant, ancestor)] ||= {}
         | 
| 463 | 
            +
                  ).map_values {|defs| defs.dup})
         | 
| 464 | 
            +
                end
         | 
| 465 | 
            +
             | 
| 466 | 
            +
                def inherit_singletons!(descendant, ancestor)
         | 
| 467 | 
            +
                  (@MethodCache[fix_module_name(descendant, ancestor)] ||= {}).each {|name, defs|
         | 
| 468 | 
            +
                    @MethodCache[descendant][name.sub('#', '.')] = defs.dup if name.ord == ?#
         | 
| 469 | 
            +
                  }
         | 
| 470 | 
            +
                end
         | 
| 471 | 
            +
             | 
| 472 | 
            +
                def fix_module_name(current, name)
         | 
| 473 | 
            +
                  if name =~ /^::/ or current == ''
         | 
| 474 | 
            +
                    current+name
         | 
| 475 | 
            +
                  elsif name == current or name == 'self'
         | 
| 476 | 
            +
                    current
         | 
| 477 | 
            +
                  elsif name !~ /^[A-Z]/
         | 
| 478 | 
            +
                    current+'#'+name
         | 
| 479 | 
            +
                  else 
         | 
| 480 | 
            +
                    path = current+'::'+name
         | 
| 481 | 
            +
                    if @MethodCache[path]
         | 
| 482 | 
            +
                      path
         | 
| 483 | 
            +
                    else 
         | 
| 484 | 
            +
                      @MethodCache[name] ||= {}
         | 
| 485 | 
            +
                      name
         | 
| 486 | 
            +
                    end
         | 
| 487 | 
            +
                  end
         | 
| 488 | 
            +
                end
         | 
| 489 | 
            +
             | 
| 490 | 
            +
                def get_lines(path)
         | 
| 491 | 
            +
                  SCRIPT_LINES__.to_a.select {|d, f| d[path]}.to_a.lasts
         | 
| 492 | 
            +
                end
         | 
| 493 | 
            +
                
         | 
| 494 | 
            +
                def print_lines(prefix, name, all)
         | 
| 495 | 
            +
                  map = lambda {|lines|
         | 
| 496 | 
            +
                      if lines.is Array
         | 
| 497 | 
            +
                        lines = SCRIPT_LINES__[lines[0]].join[lines[1]]
         | 
| 498 | 
            +
                      end
         | 
| 499 | 
            +
                      lines           }
         | 
| 500 | 
            +
                  methods = all ? @MethodCache[prefix][name].map(&map) : map.call(@MethodCache[prefix][name].last)
         | 
| 501 | 
            +
                  puts methods
         | 
| 502 | 
            +
                end
         | 
| 503 | 
            +
             | 
| 504 | 
            +
                def code_of(path, name=nil, all=false)
         | 
| 505 | 
            +
                  if name.in [true, :all]
         | 
| 506 | 
            +
                    all = true
         | 
| 507 | 
            +
                  end
         | 
| 508 | 
            +
                  if path.is String
         | 
| 509 | 
            +
                    prefix, name = path.sharp_split(/[.#]/, 2)
         | 
| 510 | 
            +
                  elsif Class === path
         | 
| 511 | 
            +
                    prefix = path.name
         | 
| 512 | 
            +
                    name = ".#{name}"
         | 
| 513 | 
            +
                  else
         | 
| 514 | 
            +
                    prefix = path.class.name
         | 
| 515 | 
            +
                    name = "##{name}"
         | 
| 516 | 
            +
                  end
         | 
| 517 | 
            +
                  if !(@MethodCache[prefix]||{})[name]
         | 
| 518 | 
            +
                    puts "looking up script lines, please wait..."
         | 
| 519 | 
            +
                    SCRIPT_LINES__.each_key {|k| parse_file k
         | 
| 520 | 
            +
                                                                break if (@MethodCache[prefix]||{})[name]
         | 
| 521 | 
            +
                    }
         | 
| 522 | 
            +
                  end
         | 
| 523 | 
            +
                  if !(@MethodCache[prefix]||{})[name]
         | 
| 524 | 
            +
                    print "nothing was found for #{prefix}#{name}"
         | 
| 525 | 
            +
                    name = name.tr('#.', '.#')
         | 
| 526 | 
            +
                    if (@MethodCache[prefix]||{})[name]
         | 
| 527 | 
            +
                      puts ", but found for #{name}:"
         | 
| 528 | 
            +
                      print_lines prefix, name, all
         | 
| 529 | 
            +
                    else  puts ''
         | 
| 530 | 
            +
                    end
         | 
| 531 | 
            +
                  else
         | 
| 532 | 
            +
                    puts "code for #{prefix}#{name}:"
         | 
| 533 | 
            +
                    print_lines prefix, name, all
         | 
| 534 | 
            +
                  end
         | 
| 535 | 
            +
                end
         | 
| 536 | 
            +
             | 
| 537 | 
            +
              end  
         | 
| 538 | 
            +
              
         | 
| 539 | 
            +
              Reader = CodeReader.new
         | 
| 540 | 
            +
            end
         | 
| 541 | 
            +
             | 
| 542 | 
            +
            module Kernel
         | 
| 543 | 
            +
              
         | 
| 544 | 
            +
              def code_of(*args)
         | 
| 545 | 
            +
                RMTools::Reader.code_of(*args)
         | 
| 546 | 
            +
              end
         | 
| 547 | 
            +
             | 
| 548 | 
            +
            end
         | 
| 549 | 
            +
             | 
| 550 | 
            +
            class Method
         | 
| 551 | 
            +
              
         | 
| 552 | 
            +
              def code(all=false)
         | 
| 553 | 
            +
                RMTools::Reader.code_of(receiver, name, all)
         | 
| 554 | 
            +
              end
         | 
| 555 | 
            +
              
         | 
| 556 | 
            +
            end
         |