analyst 0.14.2 → 0.15.0
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.
- checksums.yaml +4 -4
 - data/analyst.gemspec +3 -2
 - data/lib/analyst/entities/array.rb +15 -0
 - data/lib/analyst/entities/class.rb +6 -59
 - data/lib/analyst/entities/code_block.rb +18 -0
 - data/lib/analyst/entities/conditional.rb +19 -0
 - data/lib/analyst/entities/constant.rb +41 -0
 - data/lib/analyst/entities/entity.rb +68 -12
 - data/lib/analyst/entities/file.rb +42 -0
 - data/lib/analyst/entities/hash.rb +16 -3
 - data/lib/analyst/entities/interpolated_string.rb +3 -0
 - data/lib/analyst/entities/method.rb +15 -1
 - data/lib/analyst/entities/method_call.rb +20 -4
 - data/lib/analyst/entities/module.rb +11 -14
 - data/lib/analyst/entities/pair.rb +3 -0
 - data/lib/analyst/entities/root.rb +28 -4
 - data/lib/analyst/entities/singleton_class.rb +2 -0
 - data/lib/analyst/entities/source.rb +42 -0
 - data/lib/analyst/entities/string.rb +15 -2
 - data/lib/analyst/entities/symbol.rb +15 -2
 - data/lib/analyst/entities/{empty.rb → unhandled.rb} +3 -1
 - data/lib/analyst/parser.rb +33 -30
 - data/lib/analyst/processor.rb +25 -0
 - data/lib/analyst/version.rb +1 -1
 - data/lib/analyst.rb +18 -29
 - data/spec/class_spec.rb +1 -1
 - data/spec/constant_spec.rb +26 -0
 - data/spec/entity_spec.rb +118 -0
 - data/spec/fixtures/music.rb +19 -3
 - data/spec/parser_spec.rb +3 -2
 - data/spec/spec_helper.rb +3 -0
 - metadata +39 -30
 - data/lib/analyst/analyzer.rb +0 -162
 - data/lib/analyst/entities/begin.rb +0 -13
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 7b73349858dc8cc8e23a7bcee486149fa81fa14b
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: e8d736fd3c97802f6a8bf7db970ae730385938e0
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 121c7e0d71706490dd637a48d718002a217b4fa2c190708ed9cd8c8d2fef02758cb118f0704afbd3fa397922571f09fa9270ee2dd53eb5b68266678309d9b0cb
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 6306167886e6d7f9e4d1b6ff3bff588525805d18a6aec93b03f0c85164def809851bcfa0c54e617002813a52f43ab5a354f9e8da3f8300dadd7c71ff00539d0f
         
     | 
    
        data/analyst.gemspec
    CHANGED
    
    | 
         @@ -18,8 +18,6 @@ Gem::Specification.new do |spec| 
     | 
|
| 
       18 
18 
     | 
    
         
             
              spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
         
     | 
| 
       19 
19 
     | 
    
         
             
              spec.require_paths = ["lib"]
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
              spec.add_dependency "ephemeral", ">= 2.4.0"
         
     | 
| 
       22 
     | 
    
         
            -
              spec.add_dependency "poro_plus"
         
     | 
| 
       23 
21 
     | 
    
         
             
              spec.add_dependency "haml"
         
     | 
| 
       24 
22 
     | 
    
         
             
              spec.add_dependency "parser"
         
     | 
| 
       25 
23 
     | 
    
         
             
              spec.add_dependency "rainbow"
         
     | 
| 
         @@ -32,5 +30,8 @@ Gem::Specification.new do |spec| 
     | 
|
| 
       32 
30 
     | 
    
         
             
              spec.add_development_dependency "rspec"
         
     | 
| 
       33 
31 
     | 
    
         
             
              spec.add_development_dependency "simplecov"
         
     | 
| 
       34 
32 
     | 
    
         
             
              spec.add_development_dependency "pry"
         
     | 
| 
      
 33 
     | 
    
         
            +
              spec.add_development_dependency "byebug"
         
     | 
| 
      
 34 
     | 
    
         
            +
              spec.add_development_dependency "awesome_print"
         
     | 
| 
       35 
35 
     | 
    
         | 
| 
       36 
36 
     | 
    
         
             
            end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
         @@ -8,8 +8,14 @@ module Analyst 
     | 
|
| 
       8 
8 
     | 
    
         
             
              module Entities
         
     | 
| 
       9 
9 
     | 
    
         
             
                class Class < Analyst::Entities::Module
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
      
 11 
     | 
    
         
            +
                  handles_node :class
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
       11 
13 
     | 
    
         
             
                  alias :macros :method_calls
         
     | 
| 
       12 
14 
     | 
    
         | 
| 
      
 15 
     | 
    
         
            +
                  def kind
         
     | 
| 
      
 16 
     | 
    
         
            +
                    "Class"
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
       13 
19 
     | 
    
         
             
                  def imethods
         
     | 
| 
       14 
20 
     | 
    
         
             
                    @imethods ||= contents.select { |entity| entity.is_a? Analyst::Entities::InstanceMethod }
         
     | 
| 
       15 
21 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -36,65 +42,6 @@ module Analyst 
     | 
|
| 
       36 
42 
     | 
    
         
             
                    end
         
     | 
| 
       37 
43 
     | 
    
         
             
                  end
         
     | 
| 
       38 
44 
     | 
    
         | 
| 
       39 
     | 
    
         
            -
                  # ASSOCIATIONS = [:belongs_to, :has_one, :has_many, :has_and_belongs_to_many]
         
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
                  # attr_reader :associations
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
                  # def initialize(node, parent)
         
     | 
| 
       44 
     | 
    
         
            -
                  #   @associations = []
         
     | 
| 
       45 
     | 
    
         
            -
                  #   super
         
     | 
| 
       46 
     | 
    
         
            -
                  # end
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
                  # def handle_send(node)
         
     | 
| 
       49 
     | 
    
         
            -
                  #   target, method_name, *args = node.children
         
     | 
| 
       50 
     | 
    
         
            -
                  #   if ASSOCIATIONS.include?(method_name)
         
     | 
| 
       51 
     | 
    
         
            -
                  #     add_association(method_name, args)
         
     | 
| 
       52 
     | 
    
         
            -
                  #   end
         
     | 
| 
       53 
     | 
    
         
            -
                  # end
         
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
                  # # When a class is reopened, merge its associations
         
     | 
| 
       56 
     | 
    
         
            -
                  # def merge_associations_from(klass)
         
     | 
| 
       57 
     | 
    
         
            -
                  #   klass.associations.each do |association|
         
     | 
| 
       58 
     | 
    
         
            -
                  #     associations << Association.new(
         
     | 
| 
       59 
     | 
    
         
            -
                  #       type: association.type,
         
     | 
| 
       60 
     | 
    
         
            -
                  #       source: self,
         
     | 
| 
       61 
     | 
    
         
            -
                  #       target_class: association.target_class
         
     | 
| 
       62 
     | 
    
         
            -
                  #     )
         
     | 
| 
       63 
     | 
    
         
            -
                  #   end
         
     | 
| 
       64 
     | 
    
         
            -
                  #   associations.uniq!
         
     | 
| 
       65 
     | 
    
         
            -
                  # end
         
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
                  # private
         
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
                  # def add_association(method_name, args)
         
     | 
| 
       70 
     | 
    
         
            -
                  #   target_class = value_from_hash_node(args.last, :class_name)
         
     | 
| 
       71 
     | 
    
         
            -
                  #   target_class ||= begin
         
     | 
| 
       72 
     | 
    
         
            -
                  #                      symbol_node = args.first
         
     | 
| 
       73 
     | 
    
         
            -
                  #                      symbol_name = symbol_node.children.first
         
     | 
| 
       74 
     | 
    
         
            -
                  #                      symbol_name.pluralize.classify
         
     | 
| 
       75 
     | 
    
         
            -
                  #                    end
         
     | 
| 
       76 
     | 
    
         
            -
                  #   association = Association.new(type: method_name, source: self, target_class: target_class)
         
     | 
| 
       77 
     | 
    
         
            -
                  #   associations << association
         
     | 
| 
       78 
     | 
    
         
            -
                  # end
         
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
                  # private
         
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
                  # # Fetches value from hash node iff key is symbol and value is str
         
     | 
| 
       83 
     | 
    
         
            -
                  # # Raises an exception if value is not str
         
     | 
| 
       84 
     | 
    
         
            -
                  # # Returns nil if key is not found
         
     | 
| 
       85 
     | 
    
         
            -
                  # def value_from_hash_node(node, key)
         
     | 
| 
       86 
     | 
    
         
            -
                  #   return unless node.type == :hash
         
     | 
| 
       87 
     | 
    
         
            -
                  #   pair = node.children.detect do |pair_node|
         
     | 
| 
       88 
     | 
    
         
            -
                  #     key_symbol_node = pair_node.children.first
         
     | 
| 
       89 
     | 
    
         
            -
                  #     key == key_symbol_node.children.first
         
     | 
| 
       90 
     | 
    
         
            -
                  #   end
         
     | 
| 
       91 
     | 
    
         
            -
                  #   if pair
         
     | 
| 
       92 
     | 
    
         
            -
                  #     value_node = pair.children.last
         
     | 
| 
       93 
     | 
    
         
            -
                  #     throw "Bad type. Expected (str), got (#{value_node.type})" unless value_node.type == :str
         
     | 
| 
       94 
     | 
    
         
            -
                  #     value_node.children.first
         
     | 
| 
       95 
     | 
    
         
            -
                  #   end
         
     | 
| 
       96 
     | 
    
         
            -
                  # end
         
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
45 
     | 
    
         
             
                end
         
     | 
| 
       99 
46 
     | 
    
         | 
| 
       100 
47 
     | 
    
         
             
              end
         
     | 
| 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Analyst
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              module Entities
         
     | 
| 
      
 4 
     | 
    
         
            +
                class CodeBlock < Entity
         
     | 
| 
      
 5 
     | 
    
         
            +
                  extend Forwardable
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                  handles_node :begin
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  def_delegators :parent, :name, :full_name
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  def contents
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @contents ||= ast.children.map { |child| process_node(child) }
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,19 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Analyst
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              module Entities
         
     | 
| 
      
 4 
     | 
    
         
            +
                class Conditional < Entity
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  handles_node :if
         
     | 
| 
      
 7 
     | 
    
         
            +
                  handles_node :or
         
     | 
| 
      
 8 
     | 
    
         
            +
                  handles_node :and
         
     | 
| 
      
 9 
     | 
    
         
            +
                  handles_node :or_asgn
         
     | 
| 
      
 10 
     | 
    
         
            +
                  handles_node :and_asgn
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  private
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def contents
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @contents ||= ast.children.map { |child| process_node(child) }.compact
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,41 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Analyst
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              module Entities
         
     | 
| 
      
 4 
     | 
    
         
            +
                class Constant < Entity
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  handles_node :const
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def name
         
     | 
| 
      
 9 
     | 
    
         
            +
                    const_node_array(ast).join("::")
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  def full_name
         
     | 
| 
      
 13 
     | 
    
         
            +
                    name
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  def constants
         
     | 
| 
      
 17 
     | 
    
         
            +
                    []
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  private
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  # takes a (const) node and returns an array specifying the fully-qualified
         
     | 
| 
      
 23 
     | 
    
         
            +
                  # constant name that it represents.  ya know, so CoolModule::SubMod::SweetClass
         
     | 
| 
      
 24 
     | 
    
         
            +
                  # would be parsed to:
         
     | 
| 
      
 25 
     | 
    
         
            +
                  # (const
         
     | 
| 
      
 26 
     | 
    
         
            +
                  #   (const
         
     | 
| 
      
 27 
     | 
    
         
            +
                  #     (const nil :CoolModule) :SubMod) :SweetClass)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  # and passing that node here would return [:CoolModule, :SubMod, :SweetClass]
         
     | 
| 
      
 29 
     | 
    
         
            +
                  # TODO: should really be nested Entities::Constants all the way down.
         
     | 
| 
      
 30 
     | 
    
         
            +
                  # ((cbase) can probably use the same Entity, or maybe it's a subclass of Constant)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  def const_node_array(node)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    return [] if node.nil?
         
     | 
| 
      
 33 
     | 
    
         
            +
                    return [''] if node.type == :cbase
         
     | 
| 
      
 34 
     | 
    
         
            +
                    raise "expected (const) or (cbase) node or nil, got (#{node.type})" unless node.type == :const
         
     | 
| 
      
 35 
     | 
    
         
            +
                    const_node_array(node.children.first) << node.children[1]
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
         @@ -1,21 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative '../processor'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            # An entity is a named node of a given type which may have additional properties
         
     | 
| 
       2 
4 
     | 
    
         
             
            module Analyst
         
     | 
| 
       3 
5 
     | 
    
         
             
              module Entities
         
     | 
| 
       4 
6 
     | 
    
         
             
                class Entity
         
     | 
| 
       5 
7 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
                  attr_reader :parent
         
     | 
| 
      
 8 
     | 
    
         
            +
                  attr_reader :parent, :ast
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def self.handles_node(type)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    Analyst::Processor.register_processor(type, self)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
       7 
13 
     | 
    
         | 
| 
       8 
14 
     | 
    
         
             
                  def initialize(ast, parent)
         
     | 
| 
       9 
15 
     | 
    
         
             
                    @parent = parent
         
     | 
| 
       10 
16 
     | 
    
         
             
                    @ast = ast
         
     | 
| 
       11 
17 
     | 
    
         
             
                  end
         
     | 
| 
       12 
18 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
                  def handle_send_node(node)
         
     | 
| 
       14 
     | 
    
         
            -
                    # raise "Subclass must implement handle_send_node"
         
     | 
| 
       15 
     | 
    
         
            -
                    # abstract method.  btw, this feels wrong -- send should be an entity too.  but for now, whatevs.
         
     | 
| 
       16 
     | 
    
         
            -
                  end
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                  # TODO: should every Entity have these accessors? maybe they're mixins... but would that provide any benefit?
         
     | 
| 
       19 
19 
     | 
    
         
             
                  def classes
         
     | 
| 
       20 
20 
     | 
    
         
             
                    @classes ||= begin
         
     | 
| 
       21 
21 
     | 
    
         
             
                      nested_classes = top_level_classes.map(&:classes).flatten
         
     | 
| 
         @@ -24,6 +24,21 @@ module Analyst 
     | 
|
| 
       24 
24 
     | 
    
         
             
                    end
         
     | 
| 
       25 
25 
     | 
    
         
             
                  end
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
      
 27 
     | 
    
         
            +
                  def modules
         
     | 
| 
      
 28 
     | 
    
         
            +
                    @modules ||= begin
         
     | 
| 
      
 29 
     | 
    
         
            +
                      nested_modules = top_level_modules.map(&:modules).flatten
         
     | 
| 
      
 30 
     | 
    
         
            +
                      top_level_modules + nested_modules
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  def constants
         
     | 
| 
      
 35 
     | 
    
         
            +
                    @constants ||= top_level_constants + contents.map(&:constants).flatten
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  def top_level_constants
         
     | 
| 
      
 39 
     | 
    
         
            +
                    @top_level_constants ||= contents_of_type(Entities::Constant)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
       27 
42 
     | 
    
         
             
                  def top_level_modules
         
     | 
| 
       28 
43 
     | 
    
         
             
                    @top_level_modules ||= contents_of_type(Entities::Module)
         
     | 
| 
       29 
44 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -36,26 +51,67 @@ module Analyst 
     | 
|
| 
       36 
51 
     | 
    
         
             
                    @method_calls ||= contents_of_type(Entities::MethodCall)
         
     | 
| 
       37 
52 
     | 
    
         
             
                  end
         
     | 
| 
       38 
53 
     | 
    
         | 
| 
      
 54 
     | 
    
         
            +
                  # TODO: rethink the different kinds of Methods. there's really only one
         
     | 
| 
      
 55 
     | 
    
         
            +
                  # kind of Method, right??
         
     | 
| 
      
 56 
     | 
    
         
            +
                  # ref: http://www.devalot.com/articles/2008/09/ruby-singleton
         
     | 
| 
      
 57 
     | 
    
         
            +
                  def methods
         
     | 
| 
      
 58 
     | 
    
         
            +
                    @methods ||= contents_of_type(Entities::InstanceMethod)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                  def conditionals
         
     | 
| 
      
 62 
     | 
    
         
            +
                    @conditionals ||= contents_of_type(Entities::Conditional)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  def location
         
     | 
| 
      
 66 
     | 
    
         
            +
                    "#{file_path}:#{line_number}"
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  def file_path
         
     | 
| 
      
 70 
     | 
    
         
            +
                    parent.file_path
         
     | 
| 
      
 71 
     | 
    
         
            +
                  end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  def line_number
         
     | 
| 
      
 74 
     | 
    
         
            +
                    ast.loc.line
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                  def source
         
     | 
| 
      
 78 
     | 
    
         
            +
                    origin_source[source_range]
         
     | 
| 
      
 79 
     | 
    
         
            +
                  end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                  def origin_source
         
     | 
| 
      
 82 
     | 
    
         
            +
                    parent.origin_source
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
       39 
85 
     | 
    
         
             
                  def full_name
         
     | 
| 
       40 
86 
     | 
    
         
             
                    throw "Subclass #{self.class.name} must implement #full_name"
         
     | 
| 
       41 
87 
     | 
    
         
             
                  end
         
     | 
| 
       42 
88 
     | 
    
         | 
| 
       43 
89 
     | 
    
         
             
                  def inspect
         
     | 
| 
       44 
     | 
    
         
            -
                    "\#<#{self.class} 
     | 
| 
      
 90 
     | 
    
         
            +
                    "\#<#{self.class} location=#{location} full_name=#{full_name}>"
         
     | 
| 
       45 
91 
     | 
    
         
             
                  rescue
         
     | 
| 
       46 
     | 
    
         
            -
                    "\#<#{self.class} 
     | 
| 
      
 92 
     | 
    
         
            +
                    "\#<#{self.class} location=#{location}>"
         
     | 
| 
       47 
93 
     | 
    
         
             
                  end
         
     | 
| 
       48 
94 
     | 
    
         | 
| 
       49 
95 
     | 
    
         
             
                  private
         
     | 
| 
       50 
96 
     | 
    
         | 
| 
       51 
     | 
    
         
            -
                   
     | 
| 
      
 97 
     | 
    
         
            +
                  def source_range
         
     | 
| 
      
 98 
     | 
    
         
            +
                    Range.new(ast.loc.expression.begin_pos, ast.loc.expression.end_pos)
         
     | 
| 
      
 99 
     | 
    
         
            +
                  end
         
     | 
| 
       52 
100 
     | 
    
         | 
| 
       53 
101 
     | 
    
         
             
                  def contents_of_type(klass)
         
     | 
| 
       54 
102 
     | 
    
         
             
                    contents.select { |entity| entity.is_a? klass }
         
     | 
| 
       55 
103 
     | 
    
         
             
                  end
         
     | 
| 
       56 
104 
     | 
    
         | 
| 
       57 
105 
     | 
    
         
             
                  def contents
         
     | 
| 
       58 
     | 
    
         
            -
                    @contents ||=  
     | 
| 
      
 106 
     | 
    
         
            +
                    @contents ||= if actual_contents.is_a? Entities::CodeBlock
         
     | 
| 
      
 107 
     | 
    
         
            +
                                    actual_contents.contents
         
     | 
| 
      
 108 
     | 
    
         
            +
                                  else
         
     | 
| 
      
 109 
     | 
    
         
            +
                                    Array(actual_contents)
         
     | 
| 
      
 110 
     | 
    
         
            +
                                  end
         
     | 
| 
      
 111 
     | 
    
         
            +
                  end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                  def actual_contents
         
     | 
| 
      
 114 
     | 
    
         
            +
                    @actual_contents ||= process_node(content_node)
         
     | 
| 
       59 
115 
     | 
    
         
             
                  end
         
     | 
| 
       60 
116 
     | 
    
         | 
| 
       61 
117 
     | 
    
         
             
                  def content_node
         
     | 
| 
         @@ -63,7 +119,7 @@ module Analyst 
     | 
|
| 
       63 
119 
     | 
    
         
             
                  end
         
     | 
| 
       64 
120 
     | 
    
         | 
| 
       65 
121 
     | 
    
         
             
                  def process_node(node, parent=self)
         
     | 
| 
       66 
     | 
    
         
            -
                    Analyst:: 
     | 
| 
      
 122 
     | 
    
         
            +
                    Analyst::Processor.process_node(node, parent)
         
     | 
| 
       67 
123 
     | 
    
         
             
                  end
         
     | 
| 
       68 
124 
     | 
    
         | 
| 
       69 
125 
     | 
    
         
             
                  def process_nodes(nodes, parent=self)
         
     | 
| 
         @@ -0,0 +1,42 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Analyst
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              module Entities
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                class File < Entity
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                  handles_node :analyst_file
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  def full_name
         
     | 
| 
      
 10 
     | 
    
         
            +
                    ""
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  def file_path
         
     | 
| 
      
 14 
     | 
    
         
            +
                    parent.source_data_for(self)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  def origin_source
         
     | 
| 
      
 18 
     | 
    
         
            +
                    ::File.open(file_path, 'r').read
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def contents
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @contents ||= actual_contents.map do |child|
         
     | 
| 
      
 23 
     | 
    
         
            +
                      # skip top-level CodeBlocks
         
     | 
| 
      
 24 
     | 
    
         
            +
                      child.is_a?(Entities::CodeBlock) ? child.contents : child
         
     | 
| 
      
 25 
     | 
    
         
            +
                    end.flatten
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  private
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  def source_range
         
     | 
| 
      
 31 
     | 
    
         
            +
                    0..-1
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  def actual_contents
         
     | 
| 
      
 35 
     | 
    
         
            +
                    @actual_contents ||= ast.children.map { |child| process_node(child) }
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -2,13 +2,26 @@ module Analyst 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
              module Entities
         
     | 
| 
       4 
4 
     | 
    
         
             
                class Hash < Entity
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  handles_node :hash
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
       5 
8 
     | 
    
         
             
                  def pairs
         
     | 
| 
       6 
9 
     | 
    
         
             
                    @pairs ||= process_nodes(ast.children)
         
     | 
| 
       7 
10 
     | 
    
         
             
                  end
         
     | 
| 
       8 
11 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
                   
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
      
 12 
     | 
    
         
            +
                  # Convenience method to turn this Entity into an actual ::Hash.
         
     | 
| 
      
 13 
     | 
    
         
            +
                  # If `extract_values` is true, then all keys and values that respond
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # to `#value` will be replaced by the value they return from that call.
         
     | 
| 
      
 15 
     | 
    
         
            +
                  # Otherwise they'll be left as Analyst::Entities::Entity objects.
         
     | 
| 
      
 16 
     | 
    
         
            +
                  def to_hash(extract_values:true)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    pairs.inject({}) do |hash, pair|
         
     | 
| 
      
 18 
     | 
    
         
            +
                      key = pair.key
         
     | 
| 
      
 19 
     | 
    
         
            +
                      val = pair.value
         
     | 
| 
      
 20 
     | 
    
         
            +
                      if extract_values
         
     | 
| 
      
 21 
     | 
    
         
            +
                        key = key.value if key.respond_to?(:value)
         
     | 
| 
      
 22 
     | 
    
         
            +
                        val = val.value if val.respond_to?(:value)
         
     | 
| 
      
 23 
     | 
    
         
            +
                      end
         
     | 
| 
      
 24 
     | 
    
         
            +
                      hash[key] = val
         
     | 
| 
       12 
25 
     | 
    
         
             
                      hash
         
     | 
| 
       13 
26 
     | 
    
         
             
                    end
         
     | 
| 
       14 
27 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -2,19 +2,31 @@ module Analyst 
     | 
|
| 
       2 
2 
     | 
    
         
             
              module Entities
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
       4 
4 
     | 
    
         
             
                class InstanceMethod < Entity
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  handles_node :def
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def kind
         
     | 
| 
      
 9 
     | 
    
         
            +
                    "Instance Method"
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
       5 
12 
     | 
    
         
             
                  def name
         
     | 
| 
       6 
13 
     | 
    
         
             
                    ast.children.first.to_s
         
     | 
| 
       7 
14 
     | 
    
         
             
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
       8 
16 
     | 
    
         
             
                  def full_name
         
     | 
| 
       9 
17 
     | 
    
         
             
                    parent.full_name + '#' + name
         
     | 
| 
       10 
18 
     | 
    
         
             
                  end
         
     | 
| 
       11 
19 
     | 
    
         
             
                end
         
     | 
| 
       12 
20 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
                # TODO HERE
         
     | 
| 
       14 
21 
     | 
    
         
             
                class ClassMethod < Entity
         
     | 
| 
      
 22 
     | 
    
         
            +
                  def kind
         
     | 
| 
      
 23 
     | 
    
         
            +
                    "Class Method"
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
       15 
26 
     | 
    
         
             
                  def name
         
     | 
| 
       16 
27 
     | 
    
         
             
                    ast.children.first.to_s
         
     | 
| 
       17 
28 
     | 
    
         
             
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
       18 
30 
     | 
    
         
             
                  def full_name
         
     | 
| 
       19 
31 
     | 
    
         
             
                    parent.full_name + '::' + name
         
     | 
| 
       20 
32 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -22,6 +34,8 @@ module Analyst 
     | 
|
| 
       22 
34 
     | 
    
         | 
| 
       23 
35 
     | 
    
         
             
                class SingletonMethod < Entity
         
     | 
| 
       24 
36 
     | 
    
         | 
| 
      
 37 
     | 
    
         
            +
                  handles_node :defs
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
       25 
39 
     | 
    
         
             
                  # NOTE: not a public API -- used by Entities::Class
         
     | 
| 
       26 
40 
     | 
    
         
             
                  def target
         
     | 
| 
       27 
41 
     | 
    
         
             
                    target, name, params, content = ast.children
         
     | 
| 
         @@ -2,6 +2,8 @@ module Analyst 
     | 
|
| 
       2 
2 
     | 
    
         
             
              module Entities
         
     | 
| 
       3 
3 
     | 
    
         
             
                class MethodCall < Entity
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
      
 5 
     | 
    
         
            +
                  handles_node :send
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
       5 
7 
     | 
    
         
             
                  def name
         
     | 
| 
       6 
8 
     | 
    
         
             
                    name_node.to_s
         
     | 
| 
       7 
9 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -13,17 +15,31 @@ module Analyst 
     | 
|
| 
       13 
15 
     | 
    
         
             
                  def arguments
         
     | 
| 
       14 
16 
     | 
    
         
             
                    @arguments ||= begin
         
     | 
| 
       15 
17 
     | 
    
         
             
                      args = ast.children[2..-1]
         
     | 
| 
       16 
     | 
    
         
            -
                      args.map { |arg|  
     | 
| 
      
 18 
     | 
    
         
            +
                      args.map { |arg| process_node(arg) }
         
     | 
| 
       17 
19 
     | 
    
         
             
                    end
         
     | 
| 
       18 
20 
     | 
    
         
             
                  end
         
     | 
| 
       19 
21 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
                   
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
      
 22 
     | 
    
         
            +
                  def constants
         
     | 
| 
      
 23 
     | 
    
         
            +
                    if target.is_a? Analyst::Entities::Constant
         
     | 
| 
      
 24 
     | 
    
         
            +
                      super << target
         
     | 
| 
      
 25 
     | 
    
         
            +
                    else
         
     | 
| 
      
 26 
     | 
    
         
            +
                      super
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  private
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  def contents
         
     | 
| 
      
 33 
     | 
    
         
            +
                    arguments
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
       22 
36 
     | 
    
         
             
                  def target_node
         
     | 
| 
       23 
37 
     | 
    
         
             
                    ast.children.first
         
     | 
| 
       24 
38 
     | 
    
         
             
                  end
         
     | 
| 
       25 
39 
     | 
    
         | 
| 
       26 
     | 
    
         
            -
                   
     | 
| 
      
 40 
     | 
    
         
            +
                  def target
         
     | 
| 
      
 41 
     | 
    
         
            +
                    process_node(target_node)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
       27 
43 
     | 
    
         | 
| 
       28 
44 
     | 
    
         
             
                  def name_node
         
     | 
| 
       29 
45 
     | 
    
         
             
                    ast.children[1]
         
     | 
| 
         @@ -2,8 +2,14 @@ module Analyst 
     | 
|
| 
       2 
2 
     | 
    
         
             
              module Entities
         
     | 
| 
       3 
3 
     | 
    
         
             
                class Module < Entity
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
      
 5 
     | 
    
         
            +
                  handles_node :module
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                  def kind
         
     | 
| 
      
 8 
     | 
    
         
            +
                    "Module"
         
     | 
| 
      
 9 
     | 
    
         
            +
                  end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
       5 
11 
     | 
    
         
             
                  def name
         
     | 
| 
       6 
     | 
    
         
            -
                     
     | 
| 
      
 12 
     | 
    
         
            +
                    name_entity.name
         
     | 
| 
       7 
13 
     | 
    
         
             
                  end
         
     | 
| 
       8 
14 
     | 
    
         | 
| 
       9 
15 
     | 
    
         
             
                  def full_name
         
     | 
| 
         @@ -12,21 +18,12 @@ module Analyst 
     | 
|
| 
       12 
18 
     | 
    
         | 
| 
       13 
19 
     | 
    
         
             
                  private
         
     | 
| 
       14 
20 
     | 
    
         | 
| 
       15 
     | 
    
         
            -
                  def  
     | 
| 
       16 
     | 
    
         
            -
                     
     | 
| 
      
 21 
     | 
    
         
            +
                  def name_entity
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @name_entity ||= process_node(name_node)
         
     | 
| 
       17 
23 
     | 
    
         
             
                  end
         
     | 
| 
       18 
24 
     | 
    
         | 
| 
       19 
     | 
    
         
            -
                   
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
                  # would be parsed to:
         
     | 
| 
       22 
     | 
    
         
            -
                  # (const
         
     | 
| 
       23 
     | 
    
         
            -
                  #   (const
         
     | 
| 
       24 
     | 
    
         
            -
                  #     (const nil :CoolModule) :SubMod) :SweetClass)
         
     | 
| 
       25 
     | 
    
         
            -
                  # and passing that node here would return [:CoolModule, :SubMod, :SweetClass]
         
     | 
| 
       26 
     | 
    
         
            -
                  def const_node_array(node)
         
     | 
| 
       27 
     | 
    
         
            -
                    return [] if node.nil?
         
     | 
| 
       28 
     | 
    
         
            -
                    raise "expected (const) node or nil, got (#{node.type})" unless node.type == :const
         
     | 
| 
       29 
     | 
    
         
            -
                    const_node_array(node.children.first) << node.children[1]
         
     | 
| 
      
 25 
     | 
    
         
            +
                  def name_node
         
     | 
| 
      
 26 
     | 
    
         
            +
                    ast.children.first
         
     | 
| 
       30 
27 
     | 
    
         
             
                  end
         
     | 
| 
       31 
28 
     | 
    
         
             
                end
         
     | 
| 
       32 
29 
     | 
    
         
             
              end
         
     | 
| 
         @@ -1,19 +1,43 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Analyst
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
              module Entities
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
       4 
5 
     | 
    
         
             
                class Root < Entity
         
     | 
| 
       5 
6 
     | 
    
         | 
| 
      
 7 
     | 
    
         
            +
                  handles_node :analyst_root
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  def initialize(ast, source_data)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    @source_data = source_data
         
     | 
| 
      
 11 
     | 
    
         
            +
                    super(ast, nil)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
       6 
14 
     | 
    
         
             
                  def full_name
         
     | 
| 
       7 
15 
     | 
    
         
             
                    ""
         
     | 
| 
       8 
16 
     | 
    
         
             
                  end
         
     | 
| 
       9 
17 
     | 
    
         | 
| 
      
 18 
     | 
    
         
            +
                  def source_data_for(entity)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    source_data[actual_contents.index(entity)]
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  def file_path
         
     | 
| 
      
 23 
     | 
    
         
            +
                    throw "Entity tree malformed - Source or File should have caught this call"
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  def origin_source
         
     | 
| 
      
 27 
     | 
    
         
            +
                    throw "Entity tree malformed - Source or File hsould have caught this call"
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
       10 
30 
     | 
    
         
             
                  private
         
     | 
| 
       11 
31 
     | 
    
         | 
| 
      
 32 
     | 
    
         
            +
                  attr_reader :source_data
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
       12 
34 
     | 
    
         
             
                  def contents
         
     | 
| 
       13 
     | 
    
         
            -
                     
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
      
 35 
     | 
    
         
            +
                    # skip all top-level entities, cuz they're all Files and Sources
         
     | 
| 
      
 36 
     | 
    
         
            +
                    @contents ||= actual_contents.map(&:contents).flatten
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  def actual_contents
         
     | 
| 
      
 40 
     | 
    
         
            +
                    @actual_contents ||= ast.children.map { |child| process_node(child) }
         
     | 
| 
       17 
41 
     | 
    
         
             
                  end
         
     | 
| 
       18 
42 
     | 
    
         | 
| 
       19 
43 
     | 
    
         
             
                end
         
     | 
| 
         @@ -0,0 +1,42 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Analyst
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              module Entities
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                class Source < Entity
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                  handles_node :analyst_source
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  def full_name
         
     | 
| 
      
 10 
     | 
    
         
            +
                    ""
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  def file_path
         
     | 
| 
      
 14 
     | 
    
         
            +
                    "$PARSED FROM SOURCE$"
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  def origin_source
         
     | 
| 
      
 18 
     | 
    
         
            +
                    parent.source_data_for(self)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def contents
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @contents ||= actual_contents.map do |child|
         
     | 
| 
      
 23 
     | 
    
         
            +
                      # skip top-level CodeBlocks
         
     | 
| 
      
 24 
     | 
    
         
            +
                      child.is_a?(Entities::CodeBlock) ? child.contents : child
         
     | 
| 
      
 25 
     | 
    
         
            +
                    end.flatten
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  private
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  def source_range
         
     | 
| 
      
 31 
     | 
    
         
            +
                    0..-1
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  def actual_contents
         
     | 
| 
      
 35 
     | 
    
         
            +
                    @actual_contents ||= ast.children.map { |child| process_node(child) }
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,12 +1,25 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Analyst
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
              module Entities
         
     | 
| 
       4 
     | 
    
         
            -
                 
     | 
| 
      
 4 
     | 
    
         
            +
                class String < Entity
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
                   
     | 
| 
      
 6 
     | 
    
         
            +
                  handles_node :str
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def value
         
     | 
| 
       7 
9 
     | 
    
         
             
                    ast.children.first
         
     | 
| 
       8 
10 
     | 
    
         
             
                  end
         
     | 
| 
       9 
11 
     | 
    
         | 
| 
      
 12 
     | 
    
         
            +
                  def name
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def full_name
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  private
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  def content_node
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
       10 
23 
     | 
    
         
             
                end
         
     | 
| 
       11 
24 
     | 
    
         
             
              end
         
     | 
| 
       12 
25 
     | 
    
         
             
            end
         
     |