jbarnette (owner)

Forks

Revisions

gist: 13164 Download_button fork
public
Public Clone URL: git://gist.github.com/13164.git
Embed All Files: show embed
meta.rb #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
require "rubygems"
require "johnson"
 
require "./visitor.rb"
 
js =<<-END
function top() {
"top docstring", { command: true }
doSomething();
};
function justADocstring() {
"justADocstring docstring"
doSomething();
}
function noMeta() {
doSomething();
};
 
Namespace = {
nested: function() {
"nested docstring", { command: true }
doSomething();
},
Doubly: {
nested: function() {
"doubly nested docstring", { command: true }
doSomething();
}
}
};
var NamespaceWithVar = {
nested: function() {
"nested with var docstring", { command: true }
doSomething();
}
};
END
 
ast = Johnson.parse(js);
 
visitor = MetaVisitor.new("inlineText") do |data|
  puts data.inspect
end
 
ast.accept(visitor)
 
visitor.rb #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class Array
  def poke(item, &block)
    push(item)
    yield(item)
    pop
  end
end
 
class MetaVisitor < Johnson::Visitors::EnumeratingVisitor
  class Data
    attr_reader :name, :file, :line, :column, :docs, :extras
    
    def initialize(name, file, line, column, docs, extras={})
      @name = name
      @file = file
      @line = line
      @column = column
      @docs = docs
      @extras = extras
    end
  end
 
  def initialize(file, &block)
    @file = file
    @block = lambda {} # FIXME: refactoring Johnson to make this better
    @realblock = block
    @namespace = []
  end
 
  def visit_Function(o)
    name = (@namespace + [o.name]).compact.join(".")
    docs = extract_docs(o)
    extras = extract_extras(o)
    
    if docs
      data = Data.new(name, @file, o.line, o.column, docs, extras)
      @realblock[data]
    end
  end
 
  %w(OpEqual AssignExpr Property).each do |type|
    define_method(:"visit_#{type}") do |o|
      @namespace.poke(o.left.value) { super }
    end
  end
  
  def extract_extras(function)
    extras = {}
 
    if Johnson::Nodes::Comma === comma = function.body.value.first
      if Johnson::Nodes::ObjectLiteral === object = comma.value.last
        object.value.each do |property|
          extras[property.left.value.to_sym] = property.right.value
        end
      end
    end
    
    extras
  end
  
  def extract_docs(function)
    case node = function.body.value.first
    when Johnson::Nodes::String
      node.value
    when Johnson::Nodes::Comma
      node.value.first.value
    end
  end
end