adsl 0.0.3 → 0.1.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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -20
  3. data/README.md +14 -21
  4. data/bin/adsl-verify +8 -8
  5. data/lib/adsl.rb +3 -0
  6. data/lib/adsl/adsl.rb +3 -0
  7. data/lib/adsl/ds/data_store_spec.rb +339 -0
  8. data/lib/adsl/extract/instrumenter.rb +206 -0
  9. data/lib/adsl/extract/meta.rb +33 -0
  10. data/lib/adsl/extract/rails/action_block_builder.rb +233 -0
  11. data/lib/adsl/extract/rails/action_instrumenter.rb +400 -0
  12. data/lib/adsl/extract/rails/action_runner.rb +57 -0
  13. data/lib/adsl/extract/rails/active_record_metaclass_generator.rb +555 -0
  14. data/lib/adsl/extract/rails/callback_chain_simulator.rb +135 -0
  15. data/lib/adsl/extract/rails/invariant_extractor.rb +48 -0
  16. data/lib/adsl/extract/rails/invariant_instrumenter.rb +70 -0
  17. data/lib/adsl/extract/rails/other_meta.rb +57 -0
  18. data/lib/adsl/extract/rails/rails_extractor.rb +211 -0
  19. data/lib/adsl/extract/rails/rails_instrumentation_test_case.rb +34 -0
  20. data/lib/adsl/extract/rails/rails_special_gem_instrumentation.rb +120 -0
  21. data/lib/adsl/extract/rails/rails_test_helper.rb +140 -0
  22. data/lib/adsl/extract/sexp_utils.rb +54 -0
  23. data/lib/adsl/fol/first_order_logic.rb +261 -0
  24. data/lib/adsl/parser/adsl_parser.racc +159 -0
  25. data/lib/{parser → adsl/parser}/adsl_parser.rex +4 -4
  26. data/lib/{parser → adsl/parser}/adsl_parser.rex.rb +6 -6
  27. data/lib/adsl/parser/adsl_parser.tab.rb +1031 -0
  28. data/lib/adsl/parser/ast_nodes.rb +1410 -0
  29. data/lib/adsl/railtie.rb +67 -0
  30. data/lib/adsl/spass/bin.rb +230 -0
  31. data/lib/{spass → adsl/spass}/ruby_extensions.rb +0 -0
  32. data/lib/adsl/spass/spass_ds_extensions.rb +931 -0
  33. data/lib/adsl/spass/spass_translator.rb +393 -0
  34. data/lib/adsl/spass/util.rb +13 -0
  35. data/lib/adsl/util/csv_hash_formatter.rb +94 -0
  36. data/lib/adsl/util/general.rb +228 -0
  37. data/lib/adsl/util/test_helper.rb +71 -0
  38. data/lib/adsl/verification/formula_generators.rb +231 -0
  39. data/lib/adsl/verification/instrumentation_filter.rb +50 -0
  40. data/lib/adsl/verification/invariant.rb +19 -0
  41. data/lib/adsl/verification/rails_verification.rb +33 -0
  42. data/lib/adsl/verification/utils.rb +20 -0
  43. data/lib/adsl/verification/verification_case.rb +13 -0
  44. data/test/integration/rails/rails_branch_verification_test.rb +112 -0
  45. data/test/integration/rails/rails_verification_test.rb +253 -0
  46. data/test/integration/spass/basic_translation_test.rb +563 -0
  47. data/test/integration/spass/control_flow_translation_test.rb +421 -0
  48. data/test/unit/adsl/ds/data_store_spec_test.rb +54 -0
  49. data/test/unit/adsl/extract/instrumenter_test.rb +103 -0
  50. data/test/unit/adsl/extract/meta_test.rb +142 -0
  51. data/test/unit/adsl/extract/rails/action_block_builder_test.rb +178 -0
  52. data/test/unit/adsl/extract/rails/action_instrumenter_test.rb +68 -0
  53. data/test/unit/adsl/extract/rails/active_record_metaclass_generator_test.rb +336 -0
  54. data/test/unit/adsl/extract/rails/callback_chain_simulator_test.rb +76 -0
  55. data/test/unit/adsl/extract/rails/invariant_extractor_test.rb +92 -0
  56. data/test/unit/adsl/extract/rails/rails_extractor_test.rb +1380 -0
  57. data/test/unit/adsl/extract/rails/rails_test_helper_test.rb +25 -0
  58. data/test/unit/adsl/extract/sexp_utils_test.rb +100 -0
  59. data/test/unit/adsl/fol/first_order_logic_test.rb +227 -0
  60. data/test/unit/adsl/parser/action_parser_test.rb +1040 -0
  61. data/test/unit/adsl/parser/ast_nodes_test.rb +359 -0
  62. data/test/unit/adsl/parser/class_parser_test.rb +288 -0
  63. data/test/unit/adsl/parser/general_parser_test.rb +67 -0
  64. data/test/unit/adsl/parser/invariant_parser_test.rb +432 -0
  65. data/test/unit/adsl/parser/parser_util_test.rb +126 -0
  66. data/test/unit/adsl/spass/bin_test.rb +65 -0
  67. data/test/unit/adsl/spass/ruby_extensions_test.rb +39 -0
  68. data/test/unit/adsl/spass/spass_ds_extensions_test.rb +7 -0
  69. data/test/unit/adsl/spass/spass_translator_test.rb +342 -0
  70. data/test/unit/adsl/util/csv_hash_formatter_test.rb +68 -0
  71. data/test/unit/adsl/util/general_test.rb +303 -0
  72. data/test/unit/adsl/util/test_helper_test.rb +120 -0
  73. data/test/unit/adsl/verification/formula_generators_test.rb +200 -0
  74. data/test/unit/adsl/verification/instrumentation_filter_test.rb +39 -0
  75. data/test/unit/adsl/verification/utils_test.rb +39 -0
  76. data/test/unit/adsl/verification/verification_case_test.rb +8 -0
  77. metadata +229 -29
  78. data/lib/ds/data_store_spec.rb +0 -292
  79. data/lib/fol/first_order_logic.rb +0 -260
  80. data/lib/parser/adsl_ast.rb +0 -779
  81. data/lib/parser/adsl_parser.racc +0 -151
  82. data/lib/parser/adsl_parser.tab.rb +0 -976
  83. data/lib/parser/dsdl_parser.rex.rb +0 -196
  84. data/lib/parser/dsdl_parser.tab.rb +0 -976
  85. data/lib/spass/bin.rb +0 -164
  86. data/lib/spass/spass_ds_extensions.rb +0 -870
  87. data/lib/spass/spass_translator.rb +0 -388
  88. data/lib/spass/util.rb +0 -11
  89. data/lib/util/csv_hash_formatter.rb +0 -47
  90. data/lib/util/test_helper.rb +0 -33
  91. data/lib/util/util.rb +0 -114
@@ -0,0 +1,400 @@
1
+ require 'active_support'
2
+ require 'active_record'
3
+ require 'adsl/parser/ast_nodes'
4
+ require 'adsl/extract/instrumenter'
5
+ require 'adsl/extract/sexp_utils'
6
+ require 'adsl/extract/rails/other_meta'
7
+ require 'adsl/extract/rails/action_block_builder'
8
+ require 'adsl/extract/rails/active_record_metaclass_generator'
9
+
10
+ module Kernel
11
+ def ins_stmt(expr = nil, options = {})
12
+ if expr.is_a? Array
13
+ expr.each do |subexpr|
14
+ ins_stmt subexpr, options
15
+ end
16
+ else
17
+ stmt = ::ADSL::Extract::Rails::ActionInstrumenter.extract_stmt_from_expr expr
18
+ if stmt.is_a? ::ADSL::Parser::ASTNode and stmt.class.is_statement?
19
+ ::ADSL::Extract::Instrumenter.get_instance.abb.append_stmt stmt, options
20
+ end
21
+ end
22
+ expr
23
+ end
24
+
25
+ def ins_mark_render_statement()
26
+ ::ADSL::Parser::ASTDummyStmt.new :type => :render
27
+ end
28
+
29
+ def ins_multi_assignment(outer_binding, names, values, operator = '=')
30
+ values_to_be_returned = []
31
+ names.length.times do |index|
32
+ name = names[index]
33
+ value = values[index]
34
+
35
+ adsl_ast_name = if /^@@[^@]+$/ =~ name.to_s
36
+ "atat__#{ name.to_s[2..-1] }"
37
+ elsif /^@[^@]+$/ =~ name.to_s
38
+ "at__#{ name.to_s[1..-1] }"
39
+ elsif /^\$.*$/ =~ name.to_s
40
+ "global__#{ name.to_s[1..-1] }"
41
+ else
42
+ name.to_s
43
+ end
44
+
45
+ if value.respond_to?(:adsl_ast) && value.adsl_ast.class.is_objset?
46
+ assignment = ::ADSL::Parser::ASTAssignment.new(
47
+ :var_name => ::ADSL::Parser::ASTIdent.new(:text => adsl_ast_name),
48
+ :objset => value.adsl_ast
49
+ )
50
+ if operator == '||='
51
+ old_value = outer_binding.eval name rescue nil
52
+ if old_value.respond_to?(:adsl_ast) &&
53
+ old_value.adsl_ast.class.is_objset?
54
+ assignment = [
55
+ ::ADSL::Parser::ASTDeclareVar.new(:var_name => ::ADSL::Parser::ASTIdent.new(:text => adsl_ast_name.dup)),
56
+ ::ADSL::Parser::ASTEither.new(:blocks => [
57
+ ::ADSL::Parser::ASTBlock.new(:statements => []),
58
+ ::ADSL::Parser::ASTBlock.new(:statements => [assignment])
59
+ ])
60
+ ]
61
+ end
62
+ end
63
+ ins_stmt assignment
64
+
65
+ variable = value.nil? ? nil : value.class.new(
66
+ :adsl_ast => ::ADSL::Parser::ASTVariable.new(:var_name => ::ADSL::Parser::ASTIdent.new(:text => adsl_ast_name)
67
+ ))
68
+ outer_binding.eval "#{name} #{operator} ObjectSpace._id2ref(#{variable.object_id})"
69
+
70
+ values_to_be_returned << variable
71
+ else
72
+ outer_binding.eval "#{name} #{operator} ObjectSpace._id2ref(#{value.object_id})"
73
+ values_to_be_returned << value
74
+ end
75
+ end
76
+ names.length == 1 ? values_to_be_returned.first : values_to_be_returned
77
+ end
78
+
79
+ def ins_do_return(*return_values)
80
+ ::ADSL::Extract::Instrumenter.get_instance.abb.do_return *return_values
81
+ end
82
+
83
+ def ins_do_raise(*args)
84
+ ::ADSL::Extract::Instrumenter.get_instance.abb.do_raise *args
85
+ end
86
+
87
+ def ins_branch_choice(condition, branch_id)
88
+ ins_stmt condition
89
+ ::ADSL::Extract::Instrumenter.get_instance.abb.branch_choice branch_id
90
+ end
91
+
92
+ def ins_explore_all(method_name, &block)
93
+ instrumenter = ::ADSL::Extract::Instrumenter.get_instance
94
+
95
+ return_value = instrumenter.abb.explore_all_choices &block
96
+
97
+ block_adsl_ast = instrumenter.abb.adsl_ast
98
+
99
+ instrumenter.prev_abb << block_adsl_ast
100
+
101
+ # are we at the root level? if so, wrap everything around in an action/callback
102
+ if instrumenter.stack_depth == 2
103
+ Array.wrap(return_value).each do |final_return|
104
+ adsl_ast = ::ADSL::Extract::Rails::ActionInstrumenter.extract_stmt_from_expr final_return
105
+ block_adsl_ast.statements << adsl_ast if !adsl_ast.nil? and adsl_ast.class.is_statement?
106
+ end
107
+ instrumenter.prev_abb << ::ADSL::Parser::ASTDummyStmt.new(:type => method_name)
108
+ end
109
+
110
+ return_value
111
+ end
112
+
113
+ def ins_push_frame
114
+ instrumenter = ::ADSL::Extract::Instrumenter.get_instance
115
+ instrumenter.abb.push_frame
116
+ end
117
+
118
+ def ins_pop_frame
119
+ instrumenter = ::ADSL::Extract::Instrumenter.get_instance
120
+ instrumenter.abb.pop_frame
121
+ end
122
+
123
+ def ins_if(condition, arg1, arg2)
124
+ ins_stmt condition
125
+ push_frame_expr1, frame1_ret_value, frame1_stmts = arg1
126
+ push_frame_expr2, frame2_ret_value, frame2_stmts = arg2
127
+ if frame1_stmts.length <= 1 && frame2_stmts.length <= 1 &&
128
+ frame1_ret_value.respond_to?(:adsl_ast) && frame1_ret_value.adsl_ast.class.is_objset? &&
129
+ frame2_ret_value.respond_to?(:adsl_ast) && frame2_ret_value.adsl_ast.class.is_objset? &&
130
+ !frame1_ret_value.adsl_ast.objset_has_side_effects? && !frame2_ret_value.adsl_ast.objset_has_side_effects?
131
+
132
+ return nil if frame1_ret_value.nil? && frame2_ret_value.nil?
133
+
134
+ result_type = if frame1_ret_value.nil?
135
+ frame2_ret_value.class
136
+ elsif frame2_ret_value.nil?
137
+ frame1_ret_value.class
138
+ elsif frame1_ret_value.class <= frame2_ret_value.class
139
+ frame2_ret_value.class
140
+ elsif frame2_ret_value.class <= frame1_ret_value.class
141
+ frame1_ret_value.class
142
+ else
143
+ # objset types are incompatible
144
+ # but MRI cannot parse return statements inside an if that's being assigned
145
+ nil
146
+ end
147
+
148
+ if result_type.nil?
149
+ block1 = ::ADSL::Parser::ASTBlock.new :statements => frame1_stmts
150
+ block2 = ::ADSL::Parser::ASTBlock.new :statements => frame2_stmts
151
+ return ::ADSL::Parser::ASTEither.new :blocks => [block1, block2]
152
+ end
153
+
154
+ result_type.new(:adsl_ast => ::ADSL::Parser::ASTOneOfObjset.new(
155
+ :objsets => [frame1_ret_value.adsl_ast, frame2_ret_value.adsl_ast]
156
+ ))
157
+ else
158
+ block1 = ::ADSL::Parser::ASTBlock.new :statements => frame1_stmts
159
+ block2 = ::ADSL::Parser::ASTBlock.new :statements => frame2_stmts
160
+ ::ADSL::Parser::ASTEither.new :blocks => [block1, block2]
161
+ end
162
+ end
163
+ end
164
+
165
+ module ADSL
166
+ module Extract
167
+ module Rails
168
+
169
+ class ActionInstrumenter < ::ADSL::Extract::Instrumenter
170
+ def self.extract_stmt_from_expr(expr, method_name=nil)
171
+ adsl_ast = expr
172
+ adsl_ast = expr.adsl_ast if adsl_ast.respond_to? :adsl_ast
173
+ return nil unless adsl_ast.is_a? ::ADSL::Parser::ASTNode
174
+ return adsl_ast if adsl_ast.class.is_statement?
175
+ return ::ADSL::Parser::ASTObjsetStmt.new :objset => adsl_ast if adsl_ast.class.is_objset?
176
+ nil
177
+ end
178
+
179
+ attr_accessor :action_block
180
+
181
+ def abb
182
+ method_locals[:abb]
183
+ end
184
+
185
+ def prev_abb
186
+ previous_locals[:abb]
187
+ end
188
+
189
+ def create_locals
190
+ { :abb => ActionBlockBuilder.new }
191
+ end
192
+
193
+ def make_returns_explicit(sexp, last_stmt_index = -1)
194
+ last_stmt = sexp[last_stmt_index]
195
+ case last_stmt.sexp_type
196
+ when :block
197
+ make_returns_explicit last_stmt, -1
198
+ when :if
199
+ if last_stmt[2].nil?
200
+ last_stmt[2] = s(:return)
201
+ else
202
+ make_returns_explicit last_stmt, 2
203
+ end
204
+ if last_stmt[3].nil?
205
+ last_stmt[3] = s(:return)
206
+ else
207
+ make_returns_explicit last_stmt, 3
208
+ end
209
+ when :ensure
210
+ make_returns_explicit last_stmt, 1
211
+ when :rescue
212
+ make_returns_explicit last_stmt, 1
213
+ else
214
+ sexp[last_stmt_index] = s(:return, last_stmt) unless last_stmt.sexp_type == :return
215
+ end
216
+ end
217
+
218
+ def initialize(ar_class_names, instrument_domain = Dir.pwd)
219
+ super instrument_domain
220
+
221
+ @branch_index = 0
222
+
223
+ # remove respond_to and render
224
+ render_stmts = [:respond_to, :render, :redirect_to, :respond_with]
225
+ replace :call do |sexp|
226
+ next sexp unless sexp.length >= 3 and sexp[1].nil? and render_stmts.include?(sexp[2])
227
+ s(:call, nil, :ins_mark_render_statement)
228
+ end
229
+ replace :iter do |sexp|
230
+ next sexp unless sexp[1].length >= 3 and sexp[1][0] == :call and sexp[1][1].nil? and render_stmts.include?(sexp[1][2])
231
+ s(:call, nil, :ins_mark_render_statement)
232
+ end
233
+
234
+ # surround the entire method with a call to abb.explore_all_choices
235
+ replace :defn, :defs do |sexp|
236
+ header_elem_count = sexp.sexp_type == :defn ? 3 : 4
237
+ stmts = sexp.pop(sexp.length - header_elem_count)
238
+
239
+ single_stmt = stmts.length > 1 ? s(:block, *stmts) : stmts.first
240
+
241
+ explore_all = s(:iter,
242
+ s(:call, nil, :ins_explore_all, s(:lit, sexp[header_elem_count - 2])),
243
+ s(:args),
244
+ single_stmt)
245
+
246
+ sexp.push explore_all
247
+ sexp
248
+ end
249
+
250
+ # replace raise with ins_do_raise
251
+ replace :call do |sexp|
252
+ next sexp unless sexp[2] == :raise
253
+ s(:call, nil, :ins_do_raise)
254
+ end
255
+
256
+ # replace returns with ins_do_return
257
+ replace :return do |sexp|
258
+ s(:call, nil, :ins_do_return, *sexp.sexp_body)
259
+ end
260
+
261
+ # instrument assignments
262
+ replace :lasgn, :iasgn, :cvasgn, :cvdecl, :gasgn, :masgn, :op_asgn_or, :unless_in => [:args, :op_asgn_or] do |sexp|
263
+ next sexp if sexp.length <= 2
264
+
265
+ variables_and_prefixes = if sexp.sexp_type == :masgn
266
+ sexp[1].sexp_body.map{ |asgn_type, var| [asgn_type.to_s[0..-5], var] }
267
+ elsif sexp.sexp_type == :op_asgn_or
268
+ []
269
+ else
270
+ [[sexp[0].to_s[0..-5], sexp[1]]]
271
+ end
272
+
273
+ prepare_assignments = variables_and_prefixes.map{ |prefix, var|
274
+ s(:op_asgn_or, s("#{prefix}var".to_sym, var), s("#{prefix}asgn".to_sym, var, s(:nil)))
275
+ }
276
+
277
+ var_names = if sexp.sexp_type == :masgn
278
+ sexp[1].sexp_body.map{ |var| s(:str, var[1].to_s) }.to_a
279
+ elsif sexp.sexp_type == :op_asgn_or
280
+ [s(:str, sexp[1][1].to_s)]
281
+ else
282
+ [s(:str, sexp[1].to_s)]
283
+ end
284
+
285
+ values = if sexp.sexp_type == :masgn
286
+ sexp[2]
287
+ elsif sexp.sexp_type == :op_asgn_or
288
+ s(:array, sexp[2][2])
289
+ else
290
+ s(:array, sexp[2])
291
+ end
292
+
293
+ operator = sexp.sexp_type == :op_asgn_or ? s(:str, '||=') : s(:str, '=')
294
+
295
+ s(:block,
296
+ *prepare_assignments,
297
+ s(:call, nil, :ins_multi_assignment, s(:call, nil, :binding), s(:array, *var_names), values, operator)
298
+ )
299
+ end
300
+
301
+ # prepend ins_stmt to every non-return or non-if statement
302
+ replace :defn, :defs, :block, :iter do |sexp|
303
+ first_stmt_index = case sexp.sexp_type
304
+ when :defn; 3
305
+ when :defs; 4
306
+ when :iter; 3
307
+ when :block; 1
308
+ end
309
+ (first_stmt_index..sexp.length-1).each do |index|
310
+ unless [:if, :return].include?(sexp[index].sexp_type) ||
311
+ (sexp[index][1].nil? && [:ins_push_frame, :ins_pop_frame].include?(sexp[index][2]))
312
+ sexp[index] = s(:call, nil, :ins_stmt, sexp[index])
313
+ end
314
+ end
315
+ sexp
316
+ end
317
+
318
+ # instrument branches
319
+ replace :if do |sexp|
320
+ if sexp.may_return_or_raise?
321
+ sexp[1] = s(:call, nil, :ins_branch_choice, sexp[1], s(:lit, @branch_index += 1))
322
+ sexp[2] = s(:block, sexp[2]) unless sexp[2].nil? or sexp[2].sexp_type == :block
323
+ sexp[3] = s(:block, sexp[3]) unless sexp[3].nil? or sexp[3].sexp_type == :block
324
+ sexp
325
+ else
326
+ block1_sexp = sexp[2] || s(:nil)
327
+ block1 = block1_sexp.sexp_type == :block ? block1_sexp : s(:block, block1_sexp)
328
+ block2_sexp = sexp[3] || s(:nil)
329
+ block2 = block2_sexp.sexp_type == :block ? block2_sexp : s(:block, block2_sexp)
330
+ s(:call, nil, :ins_if,
331
+ sexp[1],
332
+ s(:array,
333
+ s(:call, nil, :ins_push_frame),
334
+ s(:splat, s(:rescue,
335
+ s(:array, block1, s(:call, nil, :ins_pop_frame)),
336
+ s(:resbody,
337
+ s(:array, s(:const, :Exception)),
338
+ s(:array, s(:nil), s(:call, nil, :ins_pop_frame))
339
+ )
340
+ ))
341
+ ),
342
+ s(:array,
343
+ s(:call, nil, :ins_push_frame),
344
+ s(:splat, s(:rescue,
345
+ s(:array, block2, s(:call, nil, :ins_pop_frame)),
346
+ s(:resbody,
347
+ s(:array, s(:const, :Exception)),
348
+ s(:array, s(:nil), s(:call, nil, :ins_pop_frame))
349
+ )
350
+ ))
351
+ )
352
+ )
353
+ end
354
+ end
355
+
356
+ # change rescue into a branch statement
357
+ replace :rescue do |sexp|
358
+ resbody = sexp.sexp_body.select{ |a| a.sexp_type == :resbody }.first
359
+ exception_type_array = s(:array, *resbody[1].sexp_body)
360
+ res_block = resbody[2..-1]
361
+ res_block = res_block.length > 1 ? s(:block, *res_block) : res_block.first
362
+ s(:if, s(:nil), res_block, sexp[1])
363
+ end
364
+
365
+ # change attrasgn into a normal call
366
+ replace :attrasgn do |sexp|
367
+ s(:call, *sexp.sexp_body)
368
+ end
369
+
370
+ # make the implicit return explicit
371
+ replace :defn, :defs do |sexp|
372
+ make_returns_explicit sexp
373
+ sexp
374
+ end
375
+
376
+ # replace calls to collection_action, member_action or page_action with a def
377
+ # these represent code sugar for defining actions with the activeadmin gem
378
+ replace :iter do |sexp|
379
+ next sexp unless (
380
+ sexp[1].sexp_type == :call &&
381
+ sexp[1][1] == nil &&
382
+ [:collection_action, :member_action, :page_action].include?(sexp[1][2])
383
+ )
384
+ s(:defn, sexp[1][3][1], sexp[2], sexp[3])
385
+ end
386
+ end
387
+
388
+ def should_instrument?(object, method_name)
389
+ return false unless super
390
+
391
+ klass = object.is_a?(Class) ? object : object.class
392
+ method = object.method method_name
393
+
394
+ klass.name.match(/^ADSL::.*$/).nil? && !(method.source_location[0] =~ /.*lib\/adsl\/.*/)
395
+ end
396
+ end
397
+
398
+ end
399
+ end
400
+ end
@@ -0,0 +1,57 @@
1
+ require 'adsl/parser/ast_nodes'
2
+
3
+ module ADSL
4
+ module Extract
5
+ module Rails
6
+ class ActionRunner
7
+ include ::ADSL::Parser
8
+
9
+ attr_reader :controller, :action
10
+
11
+ def initialize(controller, action)
12
+ @controller = controller
13
+ @action = action
14
+ end
15
+
16
+ def callbacks
17
+ @controller._process_action_callbacks
18
+ end
19
+
20
+ def root_paths_to_stmts(root_paths)
21
+ return root_paths.first.statements if root_paths.length == 1
22
+ [ASTEither.new(:blocks => root_paths)]
23
+ end
24
+
25
+ def run_action
26
+
27
+
28
+ action_root_paths = action_adsl_ast.blocks.map{ |block| [block, false] }
29
+ end
30
+
31
+ def run_before_filter(higher_root_paths)
32
+ filter_root_paths =
33
+
34
+ filter_root_paths.each do |block, chain_halted|
35
+ block += root_paths_to_stmts(higher_root_paths) unless chain_halted
36
+ end
37
+
38
+ filter_root_paths
39
+ end
40
+
41
+ def run_after_filter(higher_root_paths)
42
+ filter_root_paths =
43
+
44
+ higher_root_paths.each do |block, chain_halted|
45
+ block += root_paths_to_stmts(filter_root_paths) unless chain_halted
46
+ end
47
+
48
+ higher_root_paths
49
+ end
50
+
51
+ def run_around_filter
52
+
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end