Class: Doop::Doop

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(yaml = nil) ⇒ Doop

Returns a new instance of Doop.



16
17
18
19
20
21
22
# File 'lib/doop.rb', line 16

def initialize yaml=nil
  if yaml != nil
    @yaml = yaml
    init
  end
  setup_handlers
end

Instance Attribute Details

#yamlObject

Returns the value of attribute yaml.



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

def yaml
  @yaml
end

Instance Method Details

#[](path) ⇒ Object



59
60
61
# File 'lib/doop.rb', line 59

def [](path)
  path_elements(path).inject(@hash) { |a,n| a[n] }
end

#[]=(path, val) ⇒ Object



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

def []=(path,val)
  l = path_elements(path)
  missing = []

  # create missing nodes
  while self[construct_path(l)] == nil
    missing << l.pop
  end

  missing.reverse.each do |elem|
    self[construct_path(l)][elem] = ""
    l << elem
  end

  # set node to value
  elem = l.pop
  self[construct_path(l)][elem] = val

end

#add(path, hash = {}) ⇒ Object



91
92
93
94
# File 'lib/doop.rb', line 91

def add(path, hash={})
  self[path] = hash
  
end

#add_meta_dataObject



144
145
146
147
148
149
150
151
152
# File 'lib/doop.rb', line 144

def 
  each_question do |root, path|
    root["_open"] = false if !root.has_key?("_open")
    root["_enabled"] = true if !root.has_key?("_enabled")
    root["_answered"] = false if !root.has_key?("_answered")
    root["_answer"] = nil if !root.has_key?("_answer")
    root["_path"] = path
  end
end

#all_answered(path) ⇒ Object



304
305
306
307
308
309
# File 'lib/doop.rb', line 304

def all_answered path
  each_question(self[path], path) do |root, p|
    return false if root["_answered"] == false && root["_enabled"]
  end
  true
end

#all_nested_answered(path) ⇒ Object



232
233
234
235
236
237
238
239
240
# File 'lib/doop.rb', line 232

def all_nested_answered path
  return true if path==nil
  each_question( self[path], path ) do |root,path| 
    if root["_enabled"] 
      return false if root["_answered"] == false || root["_open"] == true
    end
  end
  true
end

#answer(context) ⇒ Object



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/doop.rb', line 187

def answer context
  path = currently_asked
  root = self[path]
  root["_answered"] = false 
  bind_params( root, context )
  res = get_handler(@on_answer_handlers, path, "_on_answer_handler").call( root, path, context, root["_answer"] )
  res = {} if ! res.is_a? Hash

  ask_next
  path = currently_asked
  return if path == nil
  each_path_elem_reverse(path) do |p|
    if all_nested_answered( p ) == true
      get_handler( @on_all_nested_answer_handlers, p, "_on_all_nested_answered" ).call( self[p], p, context )
      ask_next
    end
  end
  res
end

#answer_path(path, a, summary = nil) ⇒ Object



273
274
275
276
277
278
279
# File 'lib/doop.rb', line 273

def answer_path path, a, summary = nil
  self[path]["_answer"] = a
  self[path]["_answered"] = true
  self[path]["_summary"] = summary == nil ? a : summary
  get_top["_last_answered"] = root["_path"]
  {}
end

#answer_with(root, hash) ⇒ Object



281
282
283
284
285
# File 'lib/doop.rb', line 281

def answer_with root, hash
  root["_answered"] = true
  hash.keys.each { |k| root[k] = hash[k] }
  get_top["_last_answered"] = root["_path"]
end

#ask_nextObject



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/doop.rb', line 154

def ask_next

  q = ""
  disabled_path = nil

  each_question do |root, path|
    self[path]["_open"] = false
    next if disabled_path != nil && path.start_with?(disabled_path)
    if self[path+"/_enabled"] == false
      disabled_path = path
      next
    end

    q = path if path.start_with?("#{q}/") && root["_answered"] == false
  end

  each_path_elem( q )  { |n| self[n]["_open"] = true } 

end

#bind_params(root, context) ⇒ Object



207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/doop.rb', line 207

def bind_params root, context
  a = {}
  context.keys.each do |k|
    if k == "b_answer"
      root["_answer"] = context[k]
    else
      a[k[2..-1]] = context[k] if k.to_s.start_with?("b_")
    end
  end

  root["_answer"] = a if !a.empty?
end

#change(path) ⇒ Object



252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/doop.rb', line 252

def change path
  get_top["_last_answered"] = nil
  each_path_elem_reverse(currently_asked) do |p|
    self[p + "/_open"] = false
  end

  # open all parent questions
  each_path_elem_reverse(path) do |p|
    self[p + "/_open"] = true
    self[p + "/_answered"] = false if p != path
  end
end

#construct_path(elements) ⇒ Object



83
84
85
# File 'lib/doop.rb', line 83

def construct_path(elements)
   elements.join("/")
end

#currently_askedObject



174
175
176
177
178
179
180
181
# File 'lib/doop.rb', line 174

def currently_asked
  # get the most nested open answer
  p = ""
  each_question do |root, path|
    p = path if path.start_with?(p) && root["_open"] == true
  end
  p.empty? ? nil : p
end

#default_on_all_nested_answer(root, path, context) ⇒ Object



41
42
43
# File 'lib/doop.rb', line 41

def default_on_all_nested_answer( root, path, context )
  # do nothing
end

#default_on_answer(root, path, context, answer) ⇒ Object



45
46
47
48
49
50
51
52
53
# File 'lib/doop.rb', line 45

def default_on_answer( root, path, context, answer )

  self[path + "/_answer"] = context["answer"] if context["answer"] != nil
  self[path + "/_summary"] = context["summary"] if context["summary"] != nil
  self[path + "/_answered"] = true
  self[path + "/_open"] = false
  get_top["_last_answered"] = root["_path"]
  {}
end

#disable(path) ⇒ Object



242
243
244
245
# File 'lib/doop.rb', line 242

def disable path
  self[path + "/_enabled"] = false
  ask_next
end

#dumpObject



55
56
57
# File 'lib/doop.rb', line 55

def dump
  @hash.to_yaml
end

#each_path_elem(path) ⇒ Object



119
120
121
122
123
124
125
126
# File 'lib/doop.rb', line 119

def each_path_elem(path)
  return if path == nil
  p = ""
  path.split("/").select{|r| !r.empty?}.each do |n|
    p += "/" + n
    yield( p )
  end
end

#each_path_elem_reverse(path) ⇒ Object



128
129
130
131
132
# File 'lib/doop.rb', line 128

def each_path_elem_reverse(path)
  a = []
  each_path_elem(path) {|n| a << n }
  a.reverse.each { |n| yield(n) }
end

#each_question(root = @hash, path = "", &block) ⇒ Object



134
135
136
137
138
139
140
141
142
# File 'lib/doop.rb', line 134

def each_question(root=@hash, path="", &block) 
  root.keys.each do |key|
    next if key.start_with?("_")
    new_path = path + "/" + key
    new_root = root[key]
    block.call( new_root, new_path )
    each_question( new_root, new_path, &block )
  end
end

#each_question_with_regex_filter(regex) ⇒ Object



312
313
314
315
316
# File 'lib/doop.rb', line 312

def each_question_with_regex_filter regex
  each_question do |question,path|
    yield(question, path) if path.match( regex ) != nil
  end
end

#each_visible_questionObject



293
294
295
296
297
298
299
300
301
302
# File 'lib/doop.rb', line 293

def each_visible_question 
  open_paths = []
  each_question do |root,path|
    if root["_enabled"]
      open_paths << path if root["_open"]
      is_child = open_paths.select { |n| path.start_with?(n) && n.count('/')+1 == path.count('/') }.count > 0
      yield(root, path) if is_child || root["_open"]
    end
  end
end

#enable(path, enable = true) ⇒ Object



247
248
249
250
# File 'lib/doop.rb', line 247

def enable path, enable = true
  self[path + "/_enabled"] = enable
  ask_next
end

#get_handler(handlers, path, handler_elem) ⇒ Object



221
222
223
224
225
226
227
228
229
230
# File 'lib/doop.rb', line 221

def get_handler handlers, path, handler_elem
  handler = self[path][handler_elem]
  if handler != nil
    block = handlers[handler]
  else
    keys = handlers.keys.select { |k| path.match( "^#{k}$" ) != nil }
    block = keys.empty? ? handlers["default"] : handlers[keys[0]]
  end
  block
end

#get_topObject



318
319
320
# File 'lib/doop.rb', line 318

def get_top
  @hash[@hash.first[0]]
end

#initObject



24
25
26
27
# File 'lib/doop.rb', line 24

def init
  @hash = YAML.load( yaml )
  
end

#is_being_changed(path) ⇒ Object



326
327
328
329
# File 'lib/doop.rb', line 326

def is_being_changed path
  question = self[path]
  question[ "_enabled" ] && question[ "_answered" ] && question[ "_open" ]
end

#last_answeredObject



322
323
324
# File 'lib/doop.rb', line 322

def last_answered
  get_top[ "_last_answered"]
end

#move(from, to) ⇒ Object



102
103
104
105
106
107
# File 'lib/doop.rb', line 102

def move( from, to )
  q = self[from]
  remove(from)
  add(to)
  self[to] = q
end

#on_all_nested_answer(path, &block) ⇒ Object



269
270
271
# File 'lib/doop.rb', line 269

def on_all_nested_answer(path, &block)
  @on_all_nested_answer_handlers[path] = block
end

#on_answer(path, &block) ⇒ Object



265
266
267
# File 'lib/doop.rb', line 265

def on_answer(path, &block)
  @on_answer_handlers[path] = block
end

#path_elements(path) ⇒ Object



87
88
89
# File 'lib/doop.rb', line 87

def path_elements(path)
  path.split("/").select {|n| !n.empty? }
end

#questionObject



183
184
185
# File 'lib/doop.rb', line 183

def question
  currently_asked
end

#remove(path) ⇒ Object



96
97
98
99
100
# File 'lib/doop.rb', line 96

def remove(path)
  e = path_elements(path)
  k = e.pop
  self[construct_path(e)].delete(k)
end

#renumber(path) ⇒ Object



109
110
111
112
113
114
115
116
117
# File 'lib/doop.rb', line 109

def renumber( path )
  q = self[path]
  i = 1
  q.keys.select{|n| (n =~ /^(.*)__(\d)+/) != nil }. sort_by{|s| s.scan(/\d+/).map{|s| s.to_i}}.each do |elem|
    name = elem.match( /(.*)__\d+/)[1]
    move( "#{path}/#{elem}", "#{path}/#{name}__#{i}" )
    i+=1
  end
end

#set_yaml(yaml) ⇒ Object



29
30
31
# File 'lib/doop.rb', line 29

def set_yaml yaml
  @yaml = yaml
end

#setup_handlersObject



33
34
35
36
37
38
39
# File 'lib/doop.rb', line 33

def setup_handlers
  @on_answer_handlers = {}
  @on_answer_handlers["default"] = method(:default_on_answer)

  @on_all_nested_answer_handlers = {}
  @on_all_nested_answer_handlers["default"] = method(:default_on_all_nested_answer)
end

#unanswer_path(path) ⇒ Object



287
288
289
290
# File 'lib/doop.rb', line 287

def unanswer_path path
  self[path]["_answered"] = false
  {}
end