Module: Rubycom::Sources

Defined in:
lib/rubycom/sources.rb

Class Method Summary collapse

Class Method Details

.check(commands) ⇒ Object

Provides upfront checking for this inputs to #source_commands

Raises:

  • (ArgumentError)


23
24
25
26
27
28
# File 'lib/rubycom/sources.rb', line 23

def self.check(commands)
  raise ArgumentError, "#{commands} should be an Array but was #{commands.class}" unless commands.class == Array
  commands.each { |cmd|
    raise ArgumentError, "#{cmd} should be a Module, Method, Symbol, or String but was #{cmd.class}" unless [Module, Method, Symbol, String].include?(cmd.class)
  }
end

.map_sources(commands) ⇒ Hash

Maps each command in commands to a hash containing the command and the source string for that command. Uses #module_source and #method_source to look up source strings when command is a Module or Method.

Parameters:

  • commands (Array)

    the commands whose source should be returned

Returns:

  • (Hash)

    :command => the command from commands, :source => the source code string if the command was a Module or Method



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/rubycom/sources.rb', line 35

def self.map_sources(commands)
  commands.map { |cmd|
    {
        command: cmd,
        source: if cmd.class == Module
                  self.module_source(cmd)
                elsif cmd.class == Method
                  self.method_source(cmd)
                elsif cmd.class == Symbol || cmd.class == String
                  mod = cmd.to_s.split('::').reduce(Kernel){|last_mod, next_mod|
                    last_mod.const_get(next_mod.to_s.to_sym)
                  } rescue cmd
                  self.module_source(mod)
                else
                  cmd
                end
    }
  }
end

.method_source(method) ⇒ String

Discovers the source code for the given method.

Parameters:

  • method (Method)

    the method to be source

Returns:

  • (String)

    the source of the specified method



94
95
96
97
# File 'lib/rubycom/sources.rb', line 94

def self.method_source(method)
  return method unless method.class == Method
  method.comment + method.source
end

.module_source(mod) ⇒ String

Searches for the source location of the given module. Since modules can be defined in many locations, all source files containing a definition for the given module will be joined.

Parameters:

  • mod (Module)

    the module to be sourced

Returns:

  • (String)

    a string representing the source of the given module or an empty string if no source file could be located



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
# File 'lib/rubycom/sources.rb', line 60

def self.module_source(mod)
  return mod unless mod.class == Module
  method_sources = mod.singleton_methods(true).select { |sym| ![:included, :extended].include?(sym) }.map { |sym|
    mod.method(sym).source_location.first rescue nil
  }
  feature_sources = $LOADED_FEATURES.select{|file|
    name_match = File.dirname(file) == File.dirname(File.realpath($0))
    parent_match = File.dirname(File.dirname(file)) == File.dirname(File.dirname(File.realpath($0)))
    ancestor_match = File.dirname(File.dirname(File.dirname(file))) == File.dirname(File.dirname(File.dirname(File.realpath($0))))
    pwd_match = File.absolute_path(file).include?(Dir.pwd)
    final = if name_match || parent_match || ancestor_match || pwd_match # prevents unnecessary file reading
      (!File.read(file).match(/(class|module)\s+#{mod.name}/).nil?) rescue false
    else
      false
    end
    final
  }
  source_files = (method_sources + feature_sources).compact.uniq
  unless source_files.include?($0) # prevents unnecessary file reading
    source_files << $0 unless File.read($0).match(/(class|module)\s+#{mod.name}/).nil?
  end

  return '' if source_files.empty?
  source_files.reduce(''){|source_str, next_file|
    source_str << File.read(next_file)
    source_str << "\n" unless source_str.end_with?("\n")
    source_str
  } || ''
end

.source_command(command) ⇒ String

Calls #source_commands and filters to the source string of the first command returned

Parameters:

  • command (Array)

    the commands whose source should be returned

Returns:

  • (String)

    the source code string if the command was a Module or Method. Returns the command otherwise



9
10
11
# File 'lib/rubycom/sources.rb', line 9

def self.source_command(command)
  self.source_commands([command]).first[:source]
end

.source_commands(commands) ⇒ Hash

Checks commands then calls #map_sources

Parameters:

  • commands (Array)

    the commands whose source should be returned

Returns:

  • (Hash)

    :command => the command from commands, :source => the source code string if the command was a Module or Method



17
18
19
20
# File 'lib/rubycom/sources.rb', line 17

def self.source_commands(commands)
  com = self.check(commands)
  self.map_sources(com)
end