lev 0.0.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,127 +0,0 @@
1
- module Lev
2
-
3
- # Manages running of routines inside other routines. In the Lev context,
4
- # Handlers and Algorithms are routines. A routine and any routines nested
5
- # inside of it are executed within a single transaction, or depending on the
6
- # requirements of all the routines, no transaction at all.
7
- #
8
- # Classes that include this module get:
9
- #
10
- # 1) a "run" method for running nested routines in a standardized way.
11
- # Routines executed through the run method get hooked into the calling
12
- # hierarchy.
13
- #
14
- # 2) a "runner" accessor which points to the routine which called it. If
15
- # runner is nil that means that no other routine called it (some other
16
- # code did)
17
- #
18
- # 3) a "topmost_runner" which points to the highest routine in the calling
19
- # hierarchy (that routine whose 'runner' is nil)
20
- #
21
- # Classes that include this module must:
22
- #
23
- # 1) supply a "call" instance method (def call(*args, &block)) that passes
24
- # its arguments and block to whatever code inside the class does the work
25
- # of the class
26
- #
27
- # Classes that include this module may:
28
- #
29
- # 1) Call the class-level "uses_routine" method to indicate which other
30
- # routines will be run. Helps set isolation levels, etc. When this
31
- # method is used, the provided routine may
32
- #
33
- # 2) Set a default transaction isolation level by declaring a class method
34
- # named "default_transaction_isolation" that returns an instance of
35
- # Lev::TransactionIsolation
36
- #
37
- #
38
- module RoutineNesting
39
-
40
- def self.included(base)
41
- base.extend(ClassMethods)
42
- end
43
-
44
- module ClassMethods
45
-
46
- # Called at a routine's class level to foretell which other routines will
47
- # be used when this routine executes. Helpful for figuring out ahead of
48
- # time what kind of transaction isolation level should be used.
49
- def uses_routine(routine_class, options={})
50
- symbol = options[:as] || routine_class.name.underscore.gsub('/','_').to_sym
51
-
52
- raise IllegalArgument, "Routine #{routine_class} has already been registered" \
53
- if nested_routines[symbol]
54
-
55
- nested_routines[symbol] = routine_class
56
-
57
- transaction_isolation.replace_if_more_isolated(routine_class.transaction_isolation)
58
- end
59
-
60
- def transaction_isolation
61
- @transaction_isolation ||= default_transaction_isolation
62
- end
63
-
64
- def default_transaction_isolation
65
- TransactionIsolation.no_transaction
66
- end
67
-
68
- def nested_routines
69
- @nested_routines ||= {}
70
- end
71
-
72
- end
73
-
74
- def in_transaction(options={})
75
- if self != topmost_runner || self.class.transaction_isolation == TransactionIsolation.no_transaction
76
- yield
77
- else
78
- ActiveRecord::Base.isolation_level( self.class.transaction_isolation.symbol ) do
79
- ActiveRecord::Base.transaction { yield }
80
- end
81
- end
82
- end
83
-
84
- def run(other_routine, *args, &block)
85
- if other_routine.is_a? Symbol
86
- nested_routine = self.class.nested_routines[other_routine]
87
- if nested_routine.nil?
88
- raise IllegalArgument,
89
- "Routine symbol #{other_routine} does not point to a registered routine"
90
- end
91
- other_routine = nested_routine
92
- end
93
-
94
- other_routine = other_routine.new if other_routine.is_a? Class
95
-
96
- included_modules = other_routine.eigenclass.included_modules
97
-
98
- raise IllegalArgument, "Can only run another nested routine" \
99
- if !(included_modules.include? Lev::RoutineNesting)
100
-
101
- other_routine.runner = self
102
- other_routine.call(*args, &block)
103
- end
104
-
105
- attr_reader :runner
106
-
107
- protected
108
-
109
- attr_writer :runner
110
-
111
- def topmost_runner
112
- runner.nil? ? self : runner.topmost_runner
113
- end
114
-
115
- def runner=(runner)
116
- @runner = runner
117
-
118
- if topmost_runner.class.transaction_isolation.weaker_than(self.class.default_transaction_isolation)
119
- raise IsolationMismatch,
120
- "The routine being run has a stronger isolation requirement than " +
121
- "the isolation being used by the routine(s) running it; call the " +
122
- "'uses' method in the running routine's initializer"
123
- end
124
- end
125
-
126
- end
127
- end