active_spy 1.4.4 → 2.0.0.pre1

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.
@@ -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