Class: Cloc::FileSource

Inherits:
Object
  • Object
show all
Defined in:
lib/cloc/filesource.rb

Instance Method Summary collapse

Constructor Details

#initialize(pathname) ⇒ FileSource

Returns a new instance of FileSource.



9
10
11
12
# File 'lib/cloc/filesource.rb', line 9

def initialize(pathname)
  @pathname = pathname
  @c2r_cache = {}
end

Instance Method Details

#_c2r(cvar) ⇒ Object

Raises:



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/cloc/filesource.rb', line 64

def _c2r(cvar)
  if source =~ /#{cvar} \s* = \s* rb_define_(?:class|module) \( \s* "([^"]+)" /x
    return $1
  end
  if source =~ /#{cvar} \s* = \s* rb_define_(?:class|module)_under \( \s* (\w+) \s* , \s* "([^"]+)" /x
    return c2r($1) + '::' + $2
  end
  if source =~ /#{cvar} \s* = \s* rb_path2class \( \s* "([^"]+)" /x
    return $1
  end
  # As a last resort we use C naming conventions:
  if cvar =~ /rb_[cm](.*)/
    return $1
  end
  raise NmNtFnd
end

#c2r(cvar) ⇒ Object

Returns the fully-qualified Ruby class/module name behind a C variable.

Examples:
  "rb_mKernel" -> "Kernel"
  "cResolver" -> "YAML::Syck::Resolver"


59
60
61
62
# File 'lib/cloc/filesource.rb', line 59

def c2r(cvar)
  return @c2r_cache[cvar] if @c2r_cache[cvar]
  @c2r_cache[cvar] = _c2r(cvar)
end

#cfunctionsObject

Returns a list of all the C functions that are callable from Ruby.



44
45
46
47
48
49
50
51
52
# File 'lib/cloc/filesource.rb', line 44

def cfunctions
  @cfunction ||= begin
    list = {}
    source.scan( /\n (?:static\s+)? VALUE\s+ (\w+) \( /x ) do |func, |
      list[func] = offs_to_line($~.begin(1))
    end
    list
  end
end

#offs_to_line(offs) ⇒ Object

Converts a character offset to a line number.



37
38
39
40
41
# File 'lib/cloc/filesource.rb', line 37

def offs_to_line(offs)
  # The following isn't as inefficient as it seems: slice() returns
  # a string pointing inside the original string's allocated space.
  return source.slice(0, offs).count("\n") + 1
end

#raw_sourceObject



14
15
16
# File 'lib/cloc/filesource.rb', line 14

def raw_source
  @raw_source ||= IO.read(@pathname).gsub!(/\r?\n|\r/, "\n").freeze
end

#refsObject

Returns a list of all the method definitions.



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/cloc/filesource.rb', line 82

def refs
  errors = {}
  list = []
  source.scan( / (rb_define_method|rb_define_private_method|rb_define_singleton_method|rb_define_module_function)
                   \(
                      \s* (\w+) \s* ,
                      \s* "([^"]+)" \s* ,                                          #  "
                      \s* (\w+) /x ) do |definer, cvar, rfunc, cfunc |
    begin
      klass = c2r(cvar)
      is_singleton = (definer == 'rb_define_singleton_method' or definer == 'rb_define_module_function')
      is_instance  = (definer != 'rb_define_singleton_method')
      if is_singleton
        list << [klass + '--singleton', rfunc, cfunc]
      end
      if is_instance
        list << [klass, rfunc, cfunc]
      end
    rescue NmNtFnd
      errors[cvar] = true
    end
  end

  if Cloc.warn?
    errors.keys.each do |cvar|
      puts "-- Couldn't find variable '#{cvar}'"
    end
  end

  list
end

#sourceObject

Returns the source after processing it a bit to make it easier for other parsing functions to not care about edge cases.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/cloc/filesource.rb', line 20

def source
  return @source if defined? @source

  @source = raw_source.dup
  @source.gsub!('rb_define_global_function(', 'rb_define_module_function(rb_mKernel,')
  @source.gsub!('define_filetest_function(', 'rb_define_singleton_method(rb_cFile,')

  # Add any special cases here. As an example, here are some
  # "macro expansions" required to process DataObjects extensions.
  @source.gsub!('CONST_GET(rb_mKernel,', 'rb_path2class(')
  @source.gsub!('SQLITE3_CLASS(', 'rb_define_class_under(mSqlite3,');
  @source.gsub!('DRIVER_CLASS(', 'rb_define_class_under(mDOMysql,');

  @source.freeze
end