Module: ModuleCluster::CascadeFeatures::PerformCascades

Included in:
ModuleCluster::CascadeFeatures, Subclass
Defined in:
lib/module-cluster.rb,
lib/module-cluster/_private_/ModuleCluster/CascadeFeatures/PerformCascades.rb

Instance Method Summary collapse

Instance Method Details

#cascade_block_into_hooked_instance(module_self, action, hooked_instance, set) ⇒ Object

cascade_block_into_hooked_instance #



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/module-cluster/_private_/ModuleCluster/CascadeFeatures/PerformCascades.rb', line 131

def cascade_block_into_hooked_instance( module_self, action, hooked_instance, set )
  
  hooked_instance.extend( set.dependency_module )
        
  if hooked_instance.is_a?( Class )
    
    if action == :inherited

      unless set.dependency_module == ::ModuleCluster::CascadeFeatures::Subclass
        hooked_instance.extend( ::ModuleCluster::CascadeFeatures::Subclass )
      end
      
      hooked_instance.subclass( & set.runtime_block )

    end
    
  else

    # and we call the set's definition method to cascade
    hooked_instance.__send__( set.method, & set.runtime_block )

  end
  
end

#cascade_modules_into_hooked_instance(module_self, hooked_instance, set, modules) ⇒ Object

cascade_modules_into_hooked_instance #



117
118
119
120
121
122
123
124
125
# File 'lib/module-cluster/_private_/ModuleCluster/CascadeFeatures/PerformCascades.rb', line 117

def cascade_modules_into_hooked_instance( module_self, hooked_instance, set, modules )

  # if we are supposed to cascade we need to extend with the ::ModuleCluster dependency module
  hooked_instance.extend( set.dependency_module )

  # and we call the set's definition method to cascade
  hooked_instance.__send__( set.method, *modules )

end

#collect_block_runtime_result_modules(module_self, hooked_instance, set) ⇒ Object

collect_block_runtime_result_modules #



257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/module-cluster/_private_/ModuleCluster/CascadeFeatures/PerformCascades.rb', line 257

def collect_block_runtime_result_modules( module_self, hooked_instance, set )

  runtime_block_result_modules = nil

  block = set.runtime_includes_or_extends_block

  case block.arity
    when 0
      runtime_block_result_modules = module_self.instance_eval( & block )
    else
      runtime_block_result_modules = module_self.instance_exec( hooked_instance, 
                                                                & block )
  end
  
  if runtime_block_result_modules

    # make sure we have an array as a result
    unless runtime_block_result_modules.is_a?( Array )
      runtime_block_result_modules = [ runtime_block_result_modules ]
    end
    
    # make sure members of our result array are modules
    runtime_block_result_modules.delete_if do |this_result_instance|
      ! this_result_instance.is_a?( Module )
    end
    
    
    runtime_block_result_modules = nil if runtime_block_result_modules.empty?
    
  end
  
  return runtime_block_result_modules
  
end

#include_extend_modules(module_self, hooked_instance, set, modules) ⇒ Object

include_extend_modules #



99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/module-cluster/_private_/ModuleCluster/CascadeFeatures/PerformCascades.rb', line 99

def include_extend_modules( module_self, hooked_instance, set, modules )

  # Collect include/extend modules from this set into our eventual include/extend order.
  case set.include_or_extend
    when :include_and_extend
      include_or_extend_hooked_instance( hooked_instance, set, true, true, modules )
    when :include
      include_or_extend_hooked_instance( hooked_instance, set, true, false, modules )
    when :extend
      include_or_extend_hooked_instance( hooked_instance, set, false, true, modules )
  end
  
end

#include_or_extend_hooked_instance(hooked_instance, set, should_include, should_extend, modules) ⇒ Object

include_or_extend_hooked_instance #



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/module-cluster/_private_/ModuleCluster/CascadeFeatures/PerformCascades.rb', line 160

def include_or_extend_hooked_instance( hooked_instance, 
                                       set, 
                                       should_include, 
                                       should_extend, 
                                       modules )
  
  # We have collected includes, extends, transparent cascades.
  # Now we want to actually include/extend/cascade as appropriate.
  
  # If we have a module (a class is a module):
  module_self = self
  if hooked_instance.is_a?( Module )

    hooked_instance.module_eval do
      
      if should_include                                                                    and 
         module_self.should_include_or_extend_instance?( set.module_class_instance_or_all, 
                                                         hooked_instance )                 and 
         ! modules.empty?
         
        include( *modules.reverse )
        
      end
      
      if should_extend                                                                     and 
         module_self.should_include_or_extend_instance?( set.module_class_instance_or_all, 
                                                         hooked_instance )                 and
         ! modules.empty?
         
        extend( *modules.reverse )

      end

    end
    
  # Otherwise we have an instance:
  else
    
    if should_extend                                                                       and 
       module_self.should_include_or_extend_instance?( set.module_class_instance_or_all, 
                                                       hooked_instance )                   and 
       ! modules.empty?

      hooked_instance.extend( *modules.reverse )

    end
    
  end
  
end

#perform_cascades(module_self, action, hooked_instance, set_stack) ⇒ Object

perform_cascades #



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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/module-cluster/_private_/ModuleCluster/CascadeFeatures/PerformCascades.rb', line 8

def perform_cascades( module_self, action, hooked_instance, set_stack )

  # This method is called when a ::ModuleCluster module is included or extended.
  # It determines what modules should be included/extended and which should cascade.

  unless module_self.hooks_suspended?( action )
    
    # for each set:
    set_stack.each do |this_set|
      
      # if this particular set is suspended, skip to the next
      next if this_set.suspended
      
      # Block sets simply run a block at a hook. 
      # They do not include or extend returns from the block.
      # The hooked module will not be extended by ::ModuleCluster.
      if this_set.is_a?( ::ModuleCluster::ClusterStack::Block::Set )

        # if our blocks are set to cascade then we need to copy inherit hooks
        if this_set.dependency_module.should_cascade?( hooked_instance )
          cascade_block_into_hooked_instance( module_self, action, hooked_instance, this_set )
        end
        
        if this_set.dependency_module.should_run_block?( hooked_instance )

          case this_set.runtime_block.arity
            when 0
              module_self.instance_eval( & this_set.runtime_block )
            else
              module_self.instance_exec( hooked_instance, & this_set.runtime_block )
          end

        end
      
      # Other sets take parameters and an optional block. The optional block returns are included
      # or extended like the parameters provided.
      else

        if should_cascade = this_set.dependency_module.should_cascade?( hooked_instance )
          # cascade parameter modules as appropriate
          cascade_modules_into_hooked_instance( module_self, 
                                                hooked_instance, 
                                                this_set, 
                                                this_set.modules )
        end
      
        # dependency modules can cause instances to be included/extended and/or cascade
        should_include = this_set.dependency_module.should_include_or_extend?( hooked_instance )

        # include/extend parameter modules as appropriate
        if should_include
          include_extend_modules( module_self, hooked_instance, this_set, this_set.modules )        
        end
        
        # process runtime block if present
        if this_set.runtime_includes_or_extends_block
        
          # if we have a runtime block, run block and collect returns as appropriate
          if runtime_modules = collect_block_runtime_result_modules( module_self, 
                                                                     hooked_instance, 
                                                                     this_set )
      
            # cascade return modules if appropriate
            if should_cascade
              cascade_modules_into_hooked_instance( module_self, 
                                                    hooked_instance, 
                                                    this_set, 
                                                    runtime_modules )
            end
            
            # include/extend return modules if appropriate
            if should_include
              include_extend_modules( module_self, hooked_instance, this_set, runtime_modules )
            end
            
          end
        
        end
      
      end
    
    end
  
  end
     
end

#should_include_or_extend_instance?(module_class_instance_or_all, into_instance) ⇒ Boolean

should_include_or_extend_instance? #

Returns:

  • (Boolean)


215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/module-cluster/_private_/ModuleCluster/CascadeFeatures/PerformCascades.rb', line 215

def should_include_or_extend_instance?( module_class_instance_or_all, into_instance )

  # The set stack already corresponds to include or extend or both, 
  # we are testing all_module_class_or_instance for:
  #
  # * any include/extend
  # * module include/extend
  # * class include/extend
  # * instance extend

  should_include_or_extend_instance = false
  
  case module_class_instance_or_all
    when :all, :module_or_class_or_instance, :module_and_class_and_instance, 
         :module_class_or_instance, :module_class_and_instance, :module_class_instance
      should_include_or_extend_instance = true
    when :module_or_class, :module_and_class, :module_class
      should_include_or_extend_instance = into_instance.is_a?( Module )
    when :module_or_instance, :module_and_instance, :module_instance
      should_include_or_extend_instance = ( ! into_instance.is_a?( Module ) or
                                            ( into_instance.is_a?( Module ) && 
                                              ! into_instance.is_a?( Class ) ) )
    when :class_or_instance, :class_and_instance, :class_instance
      should_include_or_extend_instance = ( into_instance.is_a?( Class ) or
                                            ! into_instance.is_a?( Module ) )
    when :module
      should_include_or_extend_instance = ( into_instance.is_a?( Module ) && 
                                            ! into_instance.is_a?( Class ) )
    when :class
      should_include_or_extend_instance = into_instance.is_a?( Class )
    when :instance
      should_include_or_extend_instance = ! into_instance.is_a?( Module )
  end

  return should_include_or_extend_instance
  
end