active_spy 1.4.4 → 2.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,117 +0,0 @@
1
- require 'rest-client'
2
- require 'json'
3
-
4
- module ActiveSpy
5
- module Rails
6
- # Base class used to process the events received.
7
- #
8
- class Listener
9
- include ActiveSupport::Inflector
10
-
11
-
12
- # Constant to hold the model translations. The key is the incoming
13
- # +ref_type+ and the value is the matching model class.
14
- #
15
- MODEL_HANDLER = {}
16
-
17
- # Store the event handler hook in the {ActiveSpy::Rails::HookList} for
18
- # later registration of them within the event runner.
19
- #
20
- def self.inherited(child)
21
- ActiveSpy::Rails::HookList << child
22
- end
23
-
24
- # Set the external class of the model that we are listening to.
25
- #
26
- def self.external_class(klass)
27
- @external_classes = [klass]
28
- end
29
-
30
- # Set the external classes which we are listening to.
31
- #
32
- def self.external_classes(*classes)
33
- @external_classes = classes
34
- end
35
-
36
- # Convert the listener class into one or more hook hashes
37
- #
38
- def self.to_hook
39
- hooks = []
40
- hook_classes.each do |hook_class|
41
- hooks << { 'class' => hook_class, 'post_class' => name.split('Listener')[0] }
42
- end
43
- hooks
44
- end
45
-
46
- # Get the classes that we are listegnig to.
47
- #
48
- def self.hook_classes
49
- return @external_classes if defined? @external_classes
50
- [name.split('Listener')[0]]
51
- end
52
-
53
- # Handle a request with +params+ and sync the database according to
54
- # them.
55
- #
56
- def handle(params)
57
- object_type = params.delete('type')
58
- callback = params.delete('action')
59
- payload_content = params.delete('payload')[object_type.downcase]
60
- actor = params.delete('actor')
61
- realm = params.delete('realm')
62
- sync_database(callback, object_type, payload_content, actor, realm)
63
- end
64
-
65
- # Calls the proper method to sync the database. It will manipulate
66
- # objects of the class +object_type+, with the attributes sent in the
67
- # +payload+, triggered by the callback +callback+.
68
- #
69
- def sync_database(callback, object_type, payload, actor, realm)
70
- send(callback, object_type, payload, actor, realm)
71
- end
72
-
73
- # Logic to handle object's creation. You can override this, as you wish,
74
- # to suit your own needs
75
- #
76
- def create(object_type, payload, _actor, _realm)
77
- klass = get_object_class(object_type)
78
- object = klass.new
79
- object.update_attributes(payload)
80
- object
81
- end
82
-
83
- # Logic to handle object's update. You can override this, as you wish,
84
- # to suit your own needs
85
- #
86
- def update(object_type, payload, _actor, _realm)
87
- klass = get_object_class(object_type)
88
- guid = payload['guid']
89
- object = klass.find_by(guid: guid)
90
- object.update_attributes(payload)
91
- object
92
- end
93
-
94
- # Destroy a record from our database. You can override this, as you wish,
95
- # to suit your own needs
96
- #
97
- def destroy(klass, payload, _actor, _realm)
98
- klass = get_object_class(klass)
99
- guid = payload.delete('guid')
100
- object = klass.find_by(guid: guid)
101
- object.destroy!
102
- object
103
- end
104
-
105
- # Gets the object class. First, it'll look the {MODEL_HANDLER} hash and
106
- # see if there is any translation for a given +object_type+. If it does
107
- # not have a translation, this method will try to +constantize+ the
108
- # +object_type+.
109
- #
110
- def get_object_class(object_type)
111
- translated_object_type = MODEL_HANDLER[object_type]
112
- return constantize(translated_object_type) if translated_object_type
113
- constantize(object_type)
114
- end
115
- end
116
- end
117
- end
@@ -1,13 +0,0 @@
1
- require 'rails'
2
-
3
- # Railtie class to automatically include {ActiveSpy::Spy} in all
4
- # +ActiveRecord::Base+
5
- #
6
- class Railtie < Rails::Railtie
7
- initializer 'active_spy.spies' do
8
- ActiveSupport.on_load(:active_record) do
9
- include ActiveSpy::Spy
10
- include ActiveSpy::Rails::Spy
11
- end
12
- end
13
- end
@@ -1,70 +0,0 @@
1
- require 'active_support'
2
-
3
- module ActiveSpy
4
- # Module used to hold Rails specific logic.
5
- #
6
- module Rails
7
- # Module that defines methods used to spy on some class methods.
8
- #
9
- module Spy
10
- # Default snippet to extends the class with
11
- # {ActiveSpy::Spy::ClassMethods} when {ActiveSpy::Spy} is included in
12
- # it.
13
- #
14
- def self.included(base)
15
- base.extend ClassMethods
16
- end
17
- # Class methods to be defined in classes that includes {ActiveSpy::Spy}
18
- #
19
- module ClassMethods
20
- # Class method to define the realm of the model.
21
- #
22
- def model_realm(realm_name = nil)
23
- dynamically_define_method_or_call_block(:realm, realm_name)
24
- end
25
-
26
- # Class method to define the actor of the model.
27
- #
28
- def model_actor(actor_name = nil)
29
- dynamically_define_method_or_call_block(:actor, actor_name)
30
- end
31
-
32
- # Defines a method called +method_name+ that will call a method called
33
- # +method_value+ if a symbol is provided. If a block is provided
34
- # instead, it will be returned.
35
- #
36
- def dynamically_define_method_or_call_block(abstract_name, method_name)
37
- return unless method_name
38
- if abstract_name == method_name
39
- attr_accessor method_name
40
- else
41
- define_method method_name do
42
- send(:instance_variable_get, "@#{abstract_name}")
43
- end
44
- define_method "#{method_name}=" do |new_value|
45
- send(:instance_variable_set, "@#{abstract_name}", new_value)
46
- end
47
- end
48
- end
49
-
50
- # Helper to use on Rails app and watch for model creation, update and
51
- # destruction.
52
- #
53
- def watch_model_changes
54
- watch_method :save, :destroy
55
- inject_payload_for_method
56
- end
57
-
58
- # Helper to inject the method +payload_for(method)+ in the model
59
- # with the default behavior: all attributes are sent in all
60
- # actions.
61
- #
62
- def inject_payload_for_method
63
- define_method :payload_for do |_method|
64
- { self.class.name.downcase.to_sym => attributes }
65
- end
66
- end
67
- end
68
- end
69
- end
70
- end
@@ -1,87 +0,0 @@
1
- require 'json'
2
-
3
- module ActiveSpy
4
- module Rails
5
- # Module to hold classes that are intended to validate something.
6
- #
7
- module Validation
8
- # Class responsible to validate event that are send to event-runner
9
- # instances.
10
- #
11
- class Event
12
-
13
- def initialize(event_json)
14
- @event = JSON.load(event_json)
15
- end
16
-
17
- # Validates the +event_json+ provided in the initializer
18
- #
19
- # (see #initialize)
20
- def validate!
21
- check_actor_key(@event['event']['actor'])
22
- check_realm_key(@event['event']['realm'])
23
- end
24
-
25
- private
26
-
27
- # Check if actor is valid.
28
- #
29
- def check_actor_key(actor)
30
- fail ActorNotPresent if actor.nil?
31
- errors = get_errors_from_hash(actor, :actor)
32
- fail InvalidActor, errors unless errors.empty?
33
- end
34
-
35
- # Check if realm is valid.
36
- #
37
- def check_realm_key(realm)
38
- fail RealmNotPresent if realm.nil?
39
- errors = get_errors_from_hash(realm, :realm)
40
- fail InvalidRealm, errors unless errors.empty?
41
- end
42
-
43
- # Get the error from +data+ regarding +hash_type+ checking if the
44
- # required keys are being provided.
45
- #
46
- def get_errors_from_hash(data, hash_type)
47
- keys = hash_type == :actor ? required_actor_keys : required_realm_keys
48
- keys.map do |key|
49
- "#{key} should not be empty." if data[key].nil?
50
- end.compact.join(' ')
51
- end
52
-
53
- # Required keys for an actor to be valid.
54
- #
55
- def required_actor_keys
56
- %w[id class login url avatar_url]
57
- end
58
-
59
- # Required keys for realm to be valid.
60
- #
61
- def required_realm_keys
62
- %w[id class name url]
63
- end
64
- end
65
-
66
- # Error when actor is not present.
67
- #
68
- class ActorNotPresent < RuntimeError
69
- end
70
-
71
- # Error when the actor is invalid.
72
- #
73
- class InvalidActor < RuntimeError
74
- end
75
-
76
- # Error when realm is not present.
77
- #
78
- class RealmNotPresent < RuntimeError
79
- end
80
-
81
- # Error when the realm is invalid.
82
- #
83
- class InvalidRealm < RuntimeError
84
- end
85
- end
86
- end
87
- end
@@ -1,42 +0,0 @@
1
- require 'active_support'
2
-
3
- module ActiveSpy
4
- # Module that defines methods used to spy on some class methods
5
- #
6
- module Spy
7
- # Default snippet to extends the class with {ActiveSpy::Spy::ClassMethods}
8
- # when {ActiveSpy::Spy} is included in it.
9
- #
10
- def self.included(base)
11
- base.extend ClassMethods
12
- end
13
-
14
- # Invokes the callback method on the invoker class. The +callback_type+
15
- # param tells wether it will be called +:after+ or +before+.
16
- #
17
- def invoke_callback(method, callback_type)
18
- callback_invoker = callback_invoker_class.new(self)
19
- callback = "#{callback_type}_#{method}"
20
- return unless callback_invoker.respond_to?(callback)
21
- callback_invoker.send(callback)
22
- end
23
-
24
- # Gets the invoker class based on the class' name
25
- #
26
- def callback_invoker_class
27
- ActiveSupport::Inflector.constantize "#{self.class.name}Events"
28
- end
29
-
30
- # Class methods to be defined in classes that includes {ActiveSpy::Spy}
31
- #
32
- module ClassMethods
33
- # Set watchers for the +method+
34
- #
35
- def watch_method(*methods)
36
- methods.each do |method|
37
- ActiveSpy::SpyList << { 'class' => name, 'method' => method }
38
- end
39
- end
40
- end
41
- end
42
- end
@@ -1,91 +0,0 @@
1
- require 'active_support'
2
- require 'singleton'
3
-
4
- module ActiveSpy
5
- # Singleton used to hold the spies and lazely active these spies by patching
6
- # the methods in the specified classes.
7
- #
8
- class SpyList
9
- include Singleton
10
-
11
- # Just to initiliaze the spy list.
12
- #
13
- def initialize
14
- @spies = []
15
- end
16
-
17
- attr_reader :spies
18
-
19
- # Proxy all methods called in the {ActiveSpy::SpyList} class to a
20
- # {ActiveSpy::SpyList} instance. Just a syntax sugar.
21
- #
22
- def self.method_missing(method, *args, &block)
23
- instance.send(method, *args, &block)
24
- end
25
-
26
- # Activate all the spies defined in the spy list by patching the methods
27
- # in their classes.
28
- #
29
- def activate
30
- @spies.each do |spy|
31
- spied_class = spy['class']
32
- spied_method = spy['method']
33
-
34
- spy['old_method'] = patch(spied_class, spied_method) unless spy['active']
35
- spy['active'] = true
36
- end
37
- end
38
-
39
- # Deactivate all the spies defined in the spy list by unpatching the methods
40
- # in their classes.
41
- #
42
- def deactivate
43
- @spies.each do |spy|
44
- unpatch(spy['class'], spy['method'], spy['old_method'])
45
- spy['active'] = nil
46
- end
47
- end
48
-
49
- # forward {<<} method to the spy list.
50
- #
51
- def <<(other)
52
- @spies << other
53
- end
54
-
55
- private
56
-
57
- # This method patches the +method+ in the class +klass+ to invoke the
58
- # callbacks defined in the respective class, that should be named using
59
- # appending 'Events' to the class' name, and inherites from
60
- # {ActiveSpy::Base}.
61
- #
62
- def patch(klass, method)
63
- old_method = nil
64
- ActiveSupport::Inflector.constantize(klass).class_eval do
65
- old_method = instance_method(method)
66
- define_method method do |*args, &block|
67
- send(:invoke_callback, method, :before)
68
- result = old_method.bind(self).call(*args, &block)
69
- if defined?(Rails)
70
- send(:invoke_callback, method, :after) if result
71
- else
72
- send(:invoke_callback, method, :after)
73
- end
74
- result
75
- end
76
- end
77
- old_method
78
- end
79
-
80
- # Properyly unpatch the +method+ in class +klass+ and put back +old_method+
81
- # in its place.
82
- #
83
- def unpatch(klass, method, old_method)
84
- ActiveSupport::Inflector.constantize(klass).class_eval do
85
- define_method method do |*args, &block|
86
- old_method.bind(self).call(*args, &block)
87
- end
88
- end
89
- end
90
- end
91
- end