Class: Explain::Visitor

Inherits:
Object
  • Object
show all
Defined in:
lib/explain/visitor.rb

Instance Method Summary collapse

Constructor Details

#initializeVisitor

Returns a new instance of Visitor.



3
4
5
# File 'lib/explain/visitor.rb', line 3

def initialize
  @output = []
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *args, &block) ⇒ Object



295
296
297
# File 'lib/explain/visitor.rb', line 295

def method_missing(m, *args, &block)
  emit "(eerr I don't know how to explain `#{m}`)"
end

Instance Method Details

#actual_arguments(node, in_sentence = false) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
# File 'lib/explain/visitor.rb', line 168

def actual_arguments(node, in_sentence=false)
  body = node.array
  body.each_with_index do |node, index|
    visit node
    if body.length == index + 2 # last element
      emit " and "
    elsif body.length != index + 1
      emit ", "
    end
  end
end

#array_literal(node, in_sentence = false) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/explain/visitor.rb', line 96

def array_literal(node, in_sentence=false)
  body = node.body
  emit "a list of "
  body.each_with_index do |node, index|
    visit node
    if body.length == index + 2 # last element
      emit " and "
    elsif body.length != index + 1
      emit ", "
    end
  end
end

#block(node, in_sentence = false) ⇒ Object

def iter(node, in_sentence=false) end



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/explain/visitor.rb', line 186

def block(node, in_sentence=false)
  body = node.array
  body.each_with_index do |node, index|
    if body.length == index + 1 # last element
      if @in_method
      emit "Finally we return "
      end
      visit node, true
      emit "."
    else
      visit node, in_sentence
      emit '. '
    end
  end
end

#class(node, in_sentence = false) ⇒ Object



19
20
21
22
23
24
25
# File 'lib/explain/visitor.rb', line 19

def class(node, in_sentence=false)
  @in_class = node.name.name
  emit "Let's describe the general attributes and behavior of any #{node.name.name}."
  visit node.body
  emit "\nAnd with this we're done describing a #{node.name.name}."
  @in_class = nil
end

#class_scope(node, in_sentence = false) ⇒ Object Also known as: module_scope



39
40
41
# File 'lib/explain/visitor.rb', line 39

def class_scope(node, in_sentence=false)
  visit node.body
end

#define(node, in_sentence = false) ⇒ Object



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/explain/visitor.rb', line 273

def define(node, in_sentence=false)
  args = enumerate(node.arguments.names)

  if @in_class
    emit "\n\nA #{@in_class} can **#{node.name}**"
  else
    emit "\n\nLet's define a method: **#{node.name}**"
  end
  if node.arguments.names.empty?
    emit "."
  else
    emit ", given a specific #{args}." 
  end

  unless node.body.array.first.is_a?(Rubinius::AST::NilLiteral) && node.body.array.length == 1
    @in_method = true
    emit " This is described as follows: "
    visit node.body, true
    @in_method = false
  end
end

#emit(str) ⇒ Object



11
12
13
# File 'lib/explain/visitor.rb', line 11

def emit(str)
  @output.push str
end

#empty_array(node, in_sentence = false) ⇒ Object



92
93
94
# File 'lib/explain/visitor.rb', line 92

def empty_array(node, in_sentence=false)
  emit "an empty list"
end

#empty_bodyObject



35
36
37
# File 'lib/explain/visitor.rb', line 35

def empty_body(*)
  # do nothing
end

#false_literal(node, in_sentence = false) ⇒ Object



84
85
86
# File 'lib/explain/visitor.rb', line 84

def false_literal(node, in_sentence=false)
  emit "the falsehood"
end

#fixnum_literal(node, in_sentence = false) ⇒ Object



64
65
66
# File 'lib/explain/visitor.rb', line 64

def fixnum_literal(node, in_sentence=false)
  emit "the number #{node.value}"
end

#float_literal(node, in_sentence = false) ⇒ Object



68
69
70
# File 'lib/explain/visitor.rb', line 68

def float_literal(node, in_sentence=false)
  emit "the number #{node.value}"
end

#hash_literal(node, in_sentence = false) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/explain/visitor.rb', line 109

def hash_literal(node, in_sentence=false)
  return emit "an empty dictionary" if node.array.empty?

  body = node.array.each_slice(2)

  emit 'a dictionary where '
  body.each_with_index do |slice, index|
    key, value = slice

    visit key
    emit " relates to "
    visit value

    if body.to_a.length == index + 2 # last element
      emit " and "
    elsif body.to_a.length != index + 1
      emit ", "
    end
  end
end

#if(node, in_sentence = false) ⇒ Object

def scoped_constant(node, in_sentence=false) end



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/explain/visitor.rb', line 226

def if(node, in_sentence=false)
  body, else_body = node.body, node.else
  keyword = 'if'

  if node.body.is_a?(Rubinius::AST::NilLiteral) && !node.else.is_a?(Rubinius::AST::NilLiteral)

    body, else_body = else_body, body
    keyword = 'unless'
  end

  emit "#{keyword} "
  visit node.condition, true
  emit " is truthy, then "

  visit body, true

  if else_body.is_a?(Rubinius::AST::NilLiteral)
    return
  end

  emit " -- else, "

  visit else_body, true
end

#instance_variable_access(node, in_sentence = false) ⇒ Object



60
61
62
# File 'lib/explain/visitor.rb', line 60

def instance_variable_access(node, in_sentence=false)
  emit "its #{node.name[1..-1]}"
end

#instance_variable_assignment(node, in_sentence = false) ⇒ Object



54
55
56
57
58
# File 'lib/explain/visitor.rb', line 54

def instance_variable_assignment(node, in_sentence=false)
  emit in_sentence ? "i" : "I"
  emit "ts #{node.name[1..-1]} will be "
  visit(node.value)
end

#local_variable_access(node, in_sentence = false) ⇒ Object



50
51
52
# File 'lib/explain/visitor.rb', line 50

def local_variable_access(node, in_sentence=false)
  emit "what we previously defined as `#{node.name}`"
end

#local_variable_assignment(node, in_sentence = false) ⇒ Object



44
45
46
47
48
# File 'lib/explain/visitor.rb', line 44

def local_variable_assignment(node, in_sentence=false)
  emit in_sentence ? "w" : "W"
  emit "e define as `#{node.name}` "
  visit(node.value)
end

#module(node, in_sentence = false) ⇒ Object



27
28
29
30
31
32
33
# File 'lib/explain/visitor.rb', line 27

def module(node, in_sentence=false)
  @in_class = node.name.name
  emit "Let's describe a collection of behavior that we'll call #{node.name.name}."
  visit node.body
  emit "\nAnd with this we're done describing #{node.name.name}."
  @in_class = nil
end

#nil_literal(node, in_sentence = false) ⇒ Object



88
89
90
# File 'lib/explain/visitor.rb', line 88

def nil_literal(node, in_sentence=false)
  emit "the nothingness"
end

#outputObject



15
16
17
# File 'lib/explain/visitor.rb', line 15

def output
  @output.join
end

#return(node, in_sentence = false) ⇒ Object



267
268
269
270
271
# File 'lib/explain/visitor.rb', line 267

def return(node, in_sentence=false)
  emit in_sentence ? "w" : "W"
  emit "e return "
  visit node.value
end

#send(node, in_sentence = false) ⇒ Object

def regex_literal(node, in_sentence=false) end



139
140
141
142
143
144
145
146
147
148
# File 'lib/explain/visitor.rb', line 139

def send(node, in_sentence=false)
  if node.receiver.is_a?(Rubinius::AST::Self)
    emit in_sentence ? "the result of calling " : "We "
    emit "**#{node.name}**"
  else
    emit in_sentence ? "the result of calling " : "We call "
    emit "**#{node.name}** on "
    visit node.receiver
  end
end

#send_with_arguments(node, in_sentence = false) ⇒ Object



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/explain/visitor.rb', line 150

def send_with_arguments(node, in_sentence=false)
  return if process_binary_operator(node, in_sentence) # 1 * 2, a / 3, true && false

  if node.receiver.is_a?(Rubinius::AST::Self)
    emit in_sentence ? "the result of calling " : "We "
    emit "**#{node.name}**"
  else
    emit in_sentence ? "the result of calling " : "We call "
    emit "**#{node.name}** on "
    visit node.receiver
  end

  unless node.arguments.array.empty?
    emit " given "
    visit(node.arguments)
  end
end

#string_literal(node, in_sentence = false) ⇒ Object



72
73
74
# File 'lib/explain/visitor.rb', line 72

def string_literal(node, in_sentence=false)
  emit "the word \"#{node.string}\""
end

#symbol_literal(node, in_sentence = false) ⇒ Object



76
77
78
# File 'lib/explain/visitor.rb', line 76

def symbol_literal(node, in_sentence=false)
  emit "the name `#{node.value}`"
end

#true_literal(node, in_sentence = false) ⇒ Object



80
81
82
# File 'lib/explain/visitor.rb', line 80

def true_literal(node, in_sentence=false)
  emit "the truth"
end

#until(node, in_sentence = false) ⇒ Object



259
260
261
262
263
264
265
# File 'lib/explain/visitor.rb', line 259

def until(node, in_sentence=false)
  emit in_sentence ? "u" : "U"
  emit 'ntil '
  visit node.condition, true
  emit ", "
  visit node.body, true
end

#visit(node, in_sentence = false) ⇒ Object



7
8
9
# File 'lib/explain/visitor.rb', line 7

def visit(node, in_sentence=false)
  __send__ node.node_name, node, in_sentence
end

#while(node, in_sentence = false) ⇒ Object



251
252
253
254
255
256
257
# File 'lib/explain/visitor.rb', line 251

def while(node, in_sentence=false)
  emit in_sentence ? "w" : "W"
  emit 'hile '
  visit node.condition, true
  emit ", "
  visit node.body, true
end