DecodeSourceDecodeLanguageRubyParser

class Parser

The Ruby source code parser.

Definitions

def definitions_for(source, &block)

Extract definitions from the given input file.

Implementation

def definitions_for(source, &block)
	top, comments = self.parse_source(source)
	
	if top
		walk_definitions(top, comments, &block)
	end
end

def walk_definitions(node, comments, parent = nil, &block)

Walk over the syntax tree and extract relevant definitions with their associated comments.

Implementation

def walk_definitions(node, comments, parent = nil, &block)
	case node.type
	when :module
		definition = Module.new(
			node, nested_name_for(node.children[0]),
			comments: extract_comments_for(node, comments),
			parent: parent,
			language: @language, visibility: :public
		)
		
		assign_definition(parent, definition)
		
		yield definition
		
		if children = node.children[1]
			with_visibility do
				walk_definitions(children, comments, definition, &block)
			end
		end
	when :class
		definition = Class.new(
			node, nested_name_for(node.children[0]),
			comments: extract_comments_for(node, comments),
			parent: parent, language: @language, visibility: :public
		)
		
		assign_definition(parent, definition)
		
		yield definition
		
		if children = node.children[2]
			with_visibility do
				walk_definitions(children, comments, definition, &block)
			end
		end
	when :sclass
		if name = singleton_name_for(node.children[0])
			definition = Singleton.new(
				node, name,
				comments: extract_comments_for(node, comments),
				parent: parent, language: @language, visibility: :public
			)
			
			yield definition
			
			if children = node.children[1]
				walk_definitions(children, comments, definition, &block)
			end
		end
	when :def
		definition = Method.new(
			node, node.children[0],
			comments: extract_comments_for(node, comments),
			parent: parent, language: @language, visibility: @visibility
		)
		
		yield definition
	when :defs
		extracted_comments = extract_comments_for(node, comments)
		
		definition = Function.new(
			node, node.children[1],
			comments: extracted_comments,
			parent: scope_for(extracted_comments, parent, &block),
			language: @language, visibility: @visibility
		)
		
		yield definition
	when :casgn
		definition = Constant.new(
			node, node.children[1],
			comments: extract_comments_for(node, comments),
			parent: parent, language: @language
		)
		
		yield definition
	when :send
		name = node.children[1]
		
		case name
		when :public, :protected, :private
			@visibility = name
		when :private_constant
			constant_names_for(node.children[2..]) do |name|
				if definition = lookup_definition(parent, name)
					definition.visibility = :private
				end
			end
		when :attr, :attr_reader, :attr_writer, :attr_accessor
			definition = Attribute.new(
				node, name_for(node.children[2]),
				comments: extract_comments_for(node, comments),
				parent: parent, language: @language
			)
			
			yield definition
		else
			extracted_comments = extract_comments_for(node, comments)
			if kind = kind_for(node, extracted_comments)
				definition = Call.new(
					node, name_for(node, extracted_comments),
					comments: extracted_comments,
					parent: parent, language: @language
				)
				
				yield definition
			end
		end
	when :block
		extracted_comments = extract_comments_for(node, comments)
		
		if name = name_for(node, extracted_comments)
			definition = Block.new(
				node, name,
				comments: extracted_comments,
				parent: scope_for(extracted_comments, parent, &block),
				language: @language
			)
			
			if kind = kind_for(node, extracted_comments)
				definition = definition.convert(kind)
			end
			
			yield definition
			
			if children = node.children[2]
				walk_definitions(children, comments, definition, &block)
			end
		end
	else
		node.children.each do |child|
			if child.is_a?(::Parser::AST::Node)
				walk_definitions(child, comments, parent, &block) if child
			end
		end
	end
end

def segments_for(source, &block)

Extract segments from the given input file.

Implementation

def segments_for(source, &block)
	top, comments = self.parse_source(source)
	
	# We delete any leading comments:
	line = 0
	
	while comment = comments.first
		if comment.location.line == line
			comments.pop
			line += 1
		else
			break
		end
	end
	
	# Now we iterate over the syntax tree and generate segments:
	walk_segments(top, comments, &block)
end