methodmissing-scrooge 1.0.4 → 2.0.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 (58) hide show
  1. data/README.textile +139 -449
  2. data/Rakefile +20 -19
  3. data/VERSION.yml +2 -2
  4. data/lib/attributes_proxy.rb +121 -0
  5. data/lib/scrooge.rb +206 -47
  6. data/rails/init.rb +1 -10
  7. data/test/helper.rb +88 -0
  8. data/test/models/mysql_user.rb +4 -0
  9. data/test/scrooge_test.rb +75 -0
  10. data/test/setup.rb +3 -0
  11. metadata +11 -76
  12. data/assets/config/scrooge.yml.template +0 -27
  13. data/lib/scrooge/core/string.rb +0 -29
  14. data/lib/scrooge/core/symbol.rb +0 -21
  15. data/lib/scrooge/core/thread.rb +0 -26
  16. data/lib/scrooge/framework/base.rb +0 -315
  17. data/lib/scrooge/framework/rails.rb +0 -132
  18. data/lib/scrooge/middleware/tracker.rb +0 -46
  19. data/lib/scrooge/orm/active_record.rb +0 -159
  20. data/lib/scrooge/orm/base.rb +0 -102
  21. data/lib/scrooge/profile.rb +0 -223
  22. data/lib/scrooge/storage/base.rb +0 -46
  23. data/lib/scrooge/storage/memory.rb +0 -25
  24. data/lib/scrooge/strategy/base.rb +0 -74
  25. data/lib/scrooge/strategy/controller.rb +0 -31
  26. data/lib/scrooge/strategy/scope.rb +0 -15
  27. data/lib/scrooge/strategy/stage.rb +0 -77
  28. data/lib/scrooge/strategy/track.rb +0 -19
  29. data/lib/scrooge/strategy/track_then_scope.rb +0 -41
  30. data/lib/scrooge/tracker/app.rb +0 -161
  31. data/lib/scrooge/tracker/base.rb +0 -66
  32. data/lib/scrooge/tracker/model.rb +0 -150
  33. data/lib/scrooge/tracker/resource.rb +0 -181
  34. data/spec/fixtures/config/scrooge/scopes/1234567891/scope.yml +0 -2
  35. data/spec/fixtures/config/scrooge.yml +0 -20
  36. data/spec/helpers/framework/rails/cache.rb +0 -25
  37. data/spec/spec_helper.rb +0 -55
  38. data/spec/units/scrooge/core/string_spec.rb +0 -21
  39. data/spec/units/scrooge/core/symbol_spec.rb +0 -13
  40. data/spec/units/scrooge/core/thread_spec.rb +0 -15
  41. data/spec/units/scrooge/framework/base_spec.rb +0 -160
  42. data/spec/units/scrooge/framework/rails_spec.rb +0 -40
  43. data/spec/units/scrooge/orm/base_spec.rb +0 -61
  44. data/spec/units/scrooge/profile_spec.rb +0 -79
  45. data/spec/units/scrooge/storage/base_spec.rb +0 -35
  46. data/spec/units/scrooge/storage/memory_spec.rb +0 -20
  47. data/spec/units/scrooge/strategy/base_spec.rb +0 -62
  48. data/spec/units/scrooge/strategy/controller_spec.rb +0 -26
  49. data/spec/units/scrooge/strategy/scope_spec.rb +0 -18
  50. data/spec/units/scrooge/strategy/stage_spec.rb +0 -35
  51. data/spec/units/scrooge/strategy/track_spec.rb +0 -19
  52. data/spec/units/scrooge/strategy/track_then_scope_spec.rb +0 -22
  53. data/spec/units/scrooge/tracker/app_spec.rb +0 -68
  54. data/spec/units/scrooge/tracker/base_spec.rb +0 -29
  55. data/spec/units/scrooge/tracker/model_spec.rb +0 -79
  56. data/spec/units/scrooge/tracker/resource_spec.rb +0 -115
  57. data/spec/units/scrooge_spec.rb +0 -13
  58. data/tasks/scrooge.rake +0 -43
@@ -1,77 +0,0 @@
1
- module Scrooge
2
- module Strategy
3
- class Stage
4
-
5
- # Represents a duration sensitive stage / phase of execution.
6
-
7
- STATES = { :initialized => 0,
8
- :execute => 1,
9
- :terminated => 2 }
10
-
11
- attr_accessor :signature,
12
- :duration,
13
- :payload
14
-
15
- # Requires a unique signature and stores a payload for later execution.
16
- #
17
- # Valid options is
18
- # * :for : the phase / stage duration, in seconds
19
- #
20
- def initialize( signature, options = {}, &block )
21
- @signature = signature
22
- @duration = options[:for] || 0
23
- @payload = block
24
- @state = :initialized
25
- end
26
-
27
- # Always executeable when initialized and not yet terminated.
28
- #
29
- def executeable?
30
- initialized? && !terminated?
31
- end
32
-
33
- # Enter the :execute state, call the payload and sleep for the defined duration.
34
- # Returns the payload result on completion and ensures that the current state is
35
- # :terminated.
36
- #
37
- def execute!
38
- begin
39
- Scrooge::Base.profile.log( "Execute stage #{signature.inspect} ...", true)
40
- @state = :execute
41
- result = call!
42
- sleep( @duration )
43
- result
44
- ensure
45
- @state = :terminated
46
- end
47
- end
48
- alias :run! :execute!
49
-
50
- # Are we running ?
51
- #
52
- def execute?
53
- @state == :execute
54
- end
55
- alias :running? :execute?
56
-
57
- # Is this stage pending execution ?
58
- #
59
- def initialized?
60
- @state == :initialized
61
- end
62
-
63
- # Has this stage already terminated ?
64
- #
65
- def terminated?
66
- @state == :terminated
67
- end
68
-
69
- private
70
-
71
- def call! #:nodoc:
72
- Scrooge::Base.profile.instance_eval( &@payload )
73
- end
74
-
75
- end
76
- end
77
- end
@@ -1,19 +0,0 @@
1
- module Scrooge
2
- module Strategy
3
- class Track < Base
4
-
5
- stage :track, :for => Scrooge::Base.profile.warmup do
6
-
7
- log( "Tracking", true )
8
- framework.install_tracking_middleware()
9
- start_tracking!
10
- ::Kernel.at_exit do
11
- log( "Shutdown ...", true )
12
- framework.scope! if tracker.any?
13
- end
14
-
15
- end
16
-
17
- end
18
- end
19
- end
@@ -1,41 +0,0 @@
1
- module Scrooge
2
- module Strategy
3
- class TrackThenScope < Base
4
-
5
- stage :track, :for => Scrooge::Base.profile.warmup do
6
-
7
- log( "Installing tracking middleware ... ", true )
8
- framework.install_tracking_middleware()
9
- log( "Start tracking ... ", true )
10
- start_tracking!
11
-
12
- end
13
-
14
- stage :synchronize, :for => 10 do
15
-
16
- log( "Uninstalling tracking middleware ... ", true )
17
- framework.uninstall_tracking_middleware
18
- log( "Stop tracking ... ", true )
19
- stop_tracking!
20
- log( "Synchronize results with other processes ...", true )
21
- tracker.synchronize!
22
-
23
- end
24
-
25
- stage :aggregate, :for => 10 do
26
-
27
- log( "Aggregate results from other processes ...", true )
28
- tracker.aggregate!
29
-
30
- end
31
-
32
- stage :scope do
33
-
34
- log( "Scope ...", true )
35
- framework.install_scope_middleware( tracker )
36
-
37
- end
38
-
39
- end
40
- end
41
- end
@@ -1,161 +0,0 @@
1
- module Scrooge
2
- module Tracker
3
- class App < Scrooge::Tracker::Base
4
-
5
- # Application container for various Resources.
6
-
7
- GUARD = Monitor.new
8
-
9
- AGGREGATION_BUCKET = 'scrooge_tracker_aggregation'.freeze
10
-
11
- attr_accessor :resources
12
-
13
- def initialize
14
- super()
15
- @resources = Set.new
16
- end
17
-
18
- # Push this tracker instance to the framework's cache store.
19
- # A synchronization signature unique for this Process is also logged in a synchronization
20
- # bucket which maintain references to each Process's tracker.
21
- #
22
- def synchronize!
23
- GUARD.synchronize do
24
- write_cache( synchronization_signature, marshal_dump )
25
- register_synchronization_signature!
26
- end
27
- end
28
-
29
- # Process previously synchronized tracking data by recursively merging all trackers from
30
- # all Processes to have a Tracker representative of the whole cluster.
31
- #
32
- def aggregate!
33
- GUARD.synchronize do
34
- read_cache( AGGREGATION_BUCKET ).each do |tracker|
35
- tracker_data = read_cache( tracker )
36
- merge( self.class.load( tracker_data ) )
37
- end
38
- end
39
- end
40
-
41
- # Merge this Tracker with another Tracker ( multi-process aggregation )
42
- #
43
- def merge( other_tracker )
44
- return unless other_tracker
45
- resources.merge( other_tracker.resources )
46
- resources.each do |res|
47
- res.merge( other_tracker.resource( res ) )
48
- end
49
- end
50
-
51
- # Find a given resource instance
52
- #
53
- def resource( resource )
54
- resources.detect{|r| r.signature == resource.signature }
55
- end
56
-
57
- # Has any Resources been tracked ?
58
- #
59
- def any?
60
- GUARD.synchronize do
61
- !@resources.empty?
62
- end
63
- end
64
-
65
- # Add a Resource instance to this tracker.
66
- #
67
- def <<( resource )
68
- GUARD.synchronize do
69
- @resources << setup_resource( resource )
70
- end
71
- end
72
-
73
- def marshal_dump #:nodoc:
74
- GUARD.synchronize do
75
- dumped_resources()
76
- end
77
- end
78
-
79
- def marshal_load( data ) #:nodoc:
80
- GUARD.synchronize do
81
- @resources = Set.new( restored_resources( data ) )
82
- end
83
- self
84
- end
85
-
86
- # Track a given Resource.
87
- #
88
- def track( resource )
89
- begin
90
- yield
91
- ensure
92
- self << resource if resource.any?
93
- end
94
- end
95
-
96
- def inspect #:nodoc:
97
- if any?
98
- @resources.map{|r| r.inspect }.join( "\n\n" )
99
- else
100
- super
101
- end
102
- end
103
-
104
- # If we've seen this resource before, return the original, else, returns
105
- # the given resource.
106
- #
107
- def resource_for( res )
108
- resource( res ) || res
109
- end
110
-
111
- private
112
-
113
- def read_cache( key ) #:nodoc:
114
- Scrooge::Base.profile.framework.read_cache( key )
115
- end
116
-
117
- def write_cache( key, value ) #:nodoc:
118
- Scrooge::Base.profile.framework.write_cache( key, value )
119
- end
120
-
121
- def register_synchronization_signature! #:nodoc:
122
- if bucket = read_cache( AGGREGATION_BUCKET )
123
- write_cache( AGGREGATION_BUCKET, (bucket << synchronization_signature) )
124
- else
125
- write_cache( AGGREGATION_BUCKET, [synchronization_signature] )
126
- end
127
- end
128
-
129
- def synchronization_signature #:nodoc:
130
- @synchronization_signature ||= "#{Thread.current.object_id}_#{Process.pid}_#{rand(1000000)}"
131
- end
132
-
133
- def setup_resource( resource ) #:nodoc:
134
- GUARD.synchronize do
135
- resource_for( resource )
136
- end
137
- end
138
-
139
- def environment #:nodoc:
140
- profile.framework.environment
141
- end
142
-
143
- def restored_resources( data ) #:nodoc:
144
- GUARD.synchronize do
145
- data.map do |resource|
146
- Resource.load( resource )
147
- end
148
- end
149
- end
150
-
151
- def dumped_resources #:nodoc:
152
- GUARD.synchronize do
153
- @resources.to_a.map do |resource|
154
- resource.marshal_dump
155
- end
156
- end
157
- end
158
-
159
- end
160
- end
161
- end
@@ -1,66 +0,0 @@
1
- require 'set'
2
-
3
- module Scrooge
4
- module Tracker
5
-
6
- autoload :App, 'scrooge/tracker/app'
7
- autoload :Resource, 'scrooge/tracker/resource'
8
- autoload :Model, 'scrooge/tracker/model'
9
-
10
- class Base < Scrooge::Base
11
- include Comparable
12
-
13
- # Scrooge Tracker base class.
14
-
15
- class NotImplemented < StandardError
16
- end
17
-
18
- class << self
19
-
20
- # Marshal helper.
21
- #
22
- def load( data )
23
- new.marshal_load( data )
24
- end
25
-
26
- end
27
-
28
- attr_accessor :counter
29
-
30
- def initialize
31
- @counter = 0
32
- end
33
-
34
- def to_i
35
- @counter
36
- end
37
-
38
- # Requires subclasses to implement a custom marshal_dump
39
- #
40
- def marshal_dump
41
- raise NotImplemented
42
- end
43
-
44
- # Requires subclasses to implement a custom marshal_load
45
- #
46
- def marshal_load( data )
47
- raise NotImplemented
48
- end
49
-
50
- # Compare trackers through their Marshal representations.
51
- #
52
- def ==( tracker )
53
- compare_to( tracker )
54
- end
55
- alias :eql? :==
56
- alias :<=> :==
57
-
58
- private
59
-
60
- def compare_to( tracker ) #:nodoc:
61
- marshal_dump == tracker.marshal_dump
62
- end
63
-
64
- end
65
- end
66
- end
@@ -1,150 +0,0 @@
1
- module Scrooge
2
- module Tracker
3
- class Model < Base
4
-
5
- GUARD = Monitor.new
6
-
7
- attr_accessor :model,
8
- :attributes
9
-
10
- def initialize( model )
11
- super()
12
- @model = model
13
- @attributes = Set.new
14
- end
15
-
16
- # Merge this Tracker with another Tracker for the same model ( multi-process / cluster aggregation )
17
- #
18
- def merge( other_model )
19
- return unless other_model
20
- attributes.merge( other_model.attributes )
21
- end
22
-
23
- # Has any Attributes been tracked ?
24
- #
25
- def any?
26
- GUARD.synchronize do
27
- !@attributes.empty?
28
- end
29
- end
30
-
31
- # Add a Model attribute to this tracker.
32
- #
33
- def <<( attribute )
34
- GUARD.synchronize do
35
- Array( attribute ).each do |attr|
36
- attributes << attr
37
- end
38
- end
39
- end
40
-
41
- def marshal_dump #:nodoc:
42
- GUARD.synchronize do
43
- { name() => @attributes.to_a }
44
- end
45
- end
46
-
47
- def marshal_load( data ) #:nodoc:
48
- GUARD.synchronize do
49
- @model = data.keys.first
50
- @attributes = Set.new( data[@model] )
51
- self
52
- end
53
- end
54
-
55
- # Return a valid Rack middleware instance for this model.
56
- #
57
- def middleware( resource )
58
- profile.orm.scope_resource_to_model( resource, self )
59
- klass = Class.new
60
- klass.class_eval(<<-EOS, __FILE__, __LINE__)
61
-
62
- class << self
63
-
64
- def inspect
65
- "#<Scrooge::Middleware #{inspect}>"
66
- end
67
-
68
- # Around Filter compatible implementation for Rails as Dispatcher is
69
- # the root Rack application and as such don't provide access to the Rails
70
- # Routing internals from other middleware.
71
- #
72
- def filter( controller )
73
- #{model.to_s}.#{profile.orm.resource_scope_method( resource ).to_s} do
74
- yield
75
- end
76
- end
77
-
78
- end
79
-
80
- def initialize(app)
81
- @app = app
82
- end
83
-
84
- def call(env)
85
- if scope?( env )
86
- #{model.to_s}.#{profile.orm.resource_scope_method( resource ).to_s} do
87
- @app.call(env)
88
- end
89
- else
90
- @app.call(env)
91
- end
92
- end
93
-
94
- private
95
-
96
- def scope?( env )
97
- Scrooge::Base.profile.orm.resource_scope_method( resource( env ) ) == :#{profile.orm.resource_scope_method( resource ).to_s}
98
- end
99
-
100
- def resource( env )
101
- Scrooge::Base.profile.framework.resource( env )
102
- end
103
-
104
- EOS
105
- klass
106
- end
107
-
108
- # Memoize the name lookup.
109
- #
110
- def name
111
- @name ||= profile.orm.name( @model )
112
- end
113
-
114
- # Memoize the table name lookup.
115
- #
116
- def table_name
117
- @table_name ||= profile.orm.table_name( @model )
118
- end
119
-
120
- # Memoize the primary key lookup.
121
- #
122
- def primary_key
123
- @primary_key ||= profile.orm.primary_key( @model )
124
- end
125
-
126
- # Dump to a SQL SELECT snippet.
127
- #
128
- def to_sql
129
- GUARD.synchronize do
130
- attributes_with_primary_key().map{|a| "#{table_name}.#{a.to_s}" }.join(', ')
131
- end
132
- end
133
-
134
- def inspect #:nodoc:
135
- "#<#{name()} #{attributes_for_inspect}>"
136
- end
137
-
138
- private
139
-
140
- def attributes_for_inspect #:nodoc:
141
- @attributes.map{|a| ":#{a}" }.join(', ')
142
- end
143
-
144
- def attributes_with_primary_key #:nodoc:
145
- @attributes << primary_key
146
- end
147
-
148
- end
149
- end
150
- end
@@ -1,181 +0,0 @@
1
- module Scrooge
2
- module Tracker
3
- class Resource < Base
4
-
5
- # A Resource tracker is scoped to a
6
- #
7
- # * controller
8
- # * action
9
- # * request method
10
- # * content type
11
- #
12
- # and is a container for any Models referenced during the active
13
- # request / response cycle.
14
-
15
- GET = /get/i
16
-
17
- GUARD = Monitor.new
18
-
19
- attr_accessor :controller,
20
- :action,
21
- :method,
22
- :format,
23
- :models,
24
- :is_public
25
-
26
- def initialize
27
- super()
28
- @models = Set.new
29
- yield self if block_given?
30
- end
31
-
32
- # Merge this Tracker with another Tracker for the same resource ( multi-process / cluster aggregation )
33
- #
34
- def merge( other_resource )
35
- return unless other_resource
36
- models.merge( other_resource.models )
37
- models.each do |model|
38
- model.merge( other_resource.model( model ) )
39
- end
40
- end
41
-
42
- # Has any Models been tracked ?
43
- #
44
- def any?
45
- GUARD.synchronize do
46
- !@models.empty?
47
- end
48
- end
49
-
50
- # Is this a public ( not authenticated ) resource ?
51
- #
52
- def public?
53
- @is_public == true
54
- end
55
-
56
- # Is this a private ( authenticated ) resource ?
57
- #
58
- def private?
59
- !public?
60
- end
61
-
62
- # Search for a given model instance
63
- #
64
- def model( model )
65
- models.detect{|m| m.name == model.name }
66
- end
67
-
68
- # Generates a signature / lookup key.
69
- #
70
- def signature
71
- @signature ||= "#{controller.to_s}_#{action.to_s}_#{method.to_s}_#{private_or_public}"
72
- end
73
-
74
- # Only track GET requests
75
- #
76
- def trackable?
77
- !( method || '' ).to_s.match( GET ).nil?
78
- end
79
-
80
- # Add a Model to this resource.
81
- #
82
- def <<( model )
83
- GUARD.synchronize do
84
- @models << track_model_from( model )
85
- end
86
- end
87
-
88
- def marshal_dump #:nodoc:
89
- GUARD.synchronize do
90
- { signature => { :controller => @controller,
91
- :action => @action,
92
- :method => @method,
93
- :format => @format,
94
- :models => dumped_models(),
95
- :is_public => @is_public } }
96
- end
97
- end
98
-
99
- def marshal_load( data ) #:nodoc:
100
- GUARD.synchronize do
101
- data = data.to_a.flatten.last
102
- @controller = data[:controller]
103
- @action = data[:action]
104
- @method = data[:method]
105
- @format = data[:format]
106
- @models = restored_models( data[:models] )
107
- @is_public = data[:is_public]
108
- self
109
- end
110
- end
111
-
112
- # Yields a collection of Rack middleware to scope Model attributes to the
113
- # tracked dataset.
114
- #
115
- def middleware
116
- @middleware ||= begin
117
- GUARD.synchronize do
118
- models.map do |model|
119
- model.middleware( self )
120
- end
121
- end
122
- end
123
- end
124
-
125
- def inspect #:nodoc:
126
- "#<#{@method.to_s.upcase} #{private_or_public} :#{@controller}/#{@action} (#{@format})\n#{models_for_inspect()}"
127
- end
128
-
129
- private
130
-
131
- def private_or_public #:nodoc:
132
- @is_public ? 'public' : 'private'
133
- end
134
-
135
- def track_model_from( model ) #:nodoc:
136
- model.is_a?( Array ) ? model_from_enumerable( model ) : setup_model( model )
137
- end
138
-
139
- def model_from_enumerable( model ) #:nodoc:
140
- model, attribute = model
141
- model = setup_model( model )
142
- model << attribute
143
- model
144
- end
145
-
146
- def models_for_inspect #:nodoc:
147
- models.map{|m| " - #{m.inspect}" }.join( "\n" )
148
- end
149
-
150
- def dumped_models #:nodoc:
151
- GUARD.synchronize do
152
- @models.to_a.map{|m| m.marshal_dump }
153
- end
154
- end
155
-
156
- def restored_models( models ) #:nodoc:
157
- GUARD.synchronize do
158
- models.map do |model|
159
- m = model.keys.first # TODO: cleanup
160
- Model.new( m ).marshal_load( model )
161
- end.to_set
162
- end
163
- end
164
-
165
- def setup_model( model ) #:nodoc:
166
- GUARD.synchronize do
167
- if model.is_a?( Scrooge::Tracker::Model )
168
- model
169
- else
170
- model_for( model ) || Scrooge::Tracker::Model.new( model )
171
- end
172
- end
173
- end
174
-
175
- def model_for( model ) #:nodoc:
176
- @models.detect{|m| m.model.name == model.name }
177
- end
178
-
179
- end
180
- end
181
- end
@@ -1,2 +0,0 @@
1
- ---
2
- test: []