ribbon-plugins 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 230fbea0e698049dd095f097a6d977eca0e17359
4
+ data.tar.gz: 65c29190976d2a231e41493ad9840dbf9bdf90f3
5
+ SHA512:
6
+ metadata.gz: 6635638f54be4b62c15e4e988f60636d2e37d2bbb0d8686f785e2cba13a11a994d7f7a51dc664085f8cd021de9a2920a66c6a9531276b1c188cd9e7979537e8f
7
+ data.tar.gz: c70c4dec948b31c09c49e8bf61be462386095da0bce1ae5d3032b7951a46f77ec660932a3fd0a0bc7f6477f432f4c3b8b1bb0b446302477aa62bf5584298064b
@@ -0,0 +1,63 @@
1
+ class Ribbon::Plugins
2
+ class AroundStack
3
+ attr_reader :subject
4
+
5
+ def initialize(subject)
6
+ @subject = subject.to_sym
7
+ @_stack = []
8
+ end
9
+
10
+ def push(&block)
11
+ raise Errors::Error, "Must pass block" unless block_given?
12
+
13
+ AroundWrapper.new(subject, &block).tap { |wrapper|
14
+ @_stack.push(wrapper)
15
+ }
16
+ end
17
+
18
+ def call(*args, &block)
19
+ raise Errors::Error, "Must pass block" unless block_given?
20
+ call_stack = @_stack.dup
21
+
22
+ inner_most = WrappedBlock.new(&block)
23
+ call_stack.unshift(inner_most)
24
+
25
+ outer_most = call_stack.pop
26
+ outer_most.call(call_stack, *args)
27
+ end
28
+
29
+ class AroundWrapper
30
+ attr_reader :subject, :block
31
+
32
+ def initialize(subject, &block)
33
+ @subject = subject
34
+ @block = block
35
+ end
36
+
37
+ def call(call_stack, *args)
38
+ wrapped = call_stack.pop
39
+ raise Errors::Error, 'call stack too short' unless wrapped
40
+
41
+ define_singleton_method("perform_#{subject}") { |*new_args|
42
+ args = new_args unless new_args.empty?
43
+ wrapped.call(call_stack, *args)
44
+ }
45
+
46
+ instance_exec(*args, &block)
47
+ end
48
+ end
49
+
50
+ class WrappedBlock
51
+ attr_reader :block
52
+
53
+ def initialize(&block)
54
+ @block = block
55
+ end
56
+
57
+ def call(call_stack, *args)
58
+ raise Errors::Error, 'receiving non-empty call stack' unless call_stack.empty?
59
+ block.call(*args)
60
+ end
61
+ end
62
+ end # AroundStack
63
+ end # Ribbon::Plugins
@@ -0,0 +1,15 @@
1
+ class Ribbon::Plugins
2
+ class BlockStack
3
+ def initialize
4
+ @_stack = []
5
+ end
6
+
7
+ def push(&block)
8
+ @_stack.push(block)
9
+ end
10
+
11
+ def call(*args)
12
+ @_stack.reverse_each { |block| block.call(*args) }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,6 @@
1
+ class Ribbon::Plugins
2
+ module Errors
3
+ class Error < StandardError; end
4
+ class LoadError < Error; end
5
+ end
6
+ end
@@ -0,0 +1,53 @@
1
+ class Ribbon::Plugins
2
+ class Plugin
3
+ class << self
4
+ def create(&block)
5
+ Class.new(Plugin).tap { |k| k.class_eval(&block) if block }
6
+ end
7
+
8
+ def method_missing(meth, *args, &block)
9
+ if /^(before|after|around)_(\w+)$/.match(meth.to_s)
10
+ _define_callback($1, $2, &block)
11
+ else
12
+ super
13
+ end
14
+ end
15
+
16
+ def _define_callback(type, subject, &block)
17
+ _callbacks(type, subject).push(&block)
18
+ end
19
+
20
+ def _callbacks(type, subject)
21
+ ((@__callbacks ||= {})[type.to_sym] ||= {})[subject.to_sym] ||= _empty_stack_for(type, subject)
22
+ end
23
+
24
+ def _empty_stack_for(type, subject)
25
+ case type.to_sym
26
+ when :before, :after
27
+ BlockStack.new
28
+ when :around
29
+ AroundStack.new(subject)
30
+ else
31
+ raise Errors::Error, "Invalid type: #{type}"
32
+ end
33
+ end
34
+ end
35
+
36
+ def before(subject, *args)
37
+ _callbacks(:before, subject).call(*args)
38
+ end
39
+
40
+ def after(subject, *args)
41
+ _callbacks(:after, subject).call(*args)
42
+ end
43
+
44
+ def around(subject, *args, &block)
45
+ _callbacks(:around, subject).call(*args, &block)
46
+ end
47
+
48
+ private
49
+ def _callbacks(type, subject)
50
+ self.class._callbacks(type, subject)
51
+ end
52
+ end # Plugin
53
+ end # Ribbon::Plugins
@@ -0,0 +1,5 @@
1
+ module Ribbon
2
+ class Plugins
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,89 @@
1
+ require 'ribbon/plugins/version'
2
+
3
+ module Ribbon
4
+ class Plugins
5
+ autoload(:Errors, 'ribbon/plugins/errors')
6
+ autoload(:Plugin, 'ribbon/plugins/plugin')
7
+ autoload(:AroundStack, 'ribbon/plugins/around_stack')
8
+ autoload(:BlockStack, 'ribbon/plugins/block_stack')
9
+
10
+ def initialize(plugin_module=nil)
11
+ @_plugin_module = plugin_module
12
+ end
13
+
14
+ def add(plugin=nil, &block)
15
+ plugin = _load(plugin, &block)
16
+ _add_plugin(plugin.new)
17
+ end
18
+
19
+ def clear
20
+ @_plugins = []
21
+ nil
22
+ end
23
+
24
+ def before(subject, *args)
25
+ _plugins.reverse_each { |plugin| plugin.before(subject, *args) }
26
+ end
27
+
28
+ def after(subject, *args)
29
+ _plugins.reverse_each { |plugin| plugin.after(subject, *args) }
30
+ end
31
+
32
+ def around(subject, *args, &block)
33
+ _around_stack.call(subject, *args) { |subject, *args| block.call(*args) }
34
+ end
35
+
36
+ def perform(subject, *args, &block)
37
+ before(subject, *args)
38
+ around(subject, *args, &block)
39
+ after(subject, *args)
40
+ end
41
+
42
+ private
43
+ def _plugins
44
+ @_plugins ||= []
45
+ end
46
+
47
+ def _around_stack
48
+ @__around_stack ||= AroundStack.new(:block)
49
+ end
50
+
51
+ def _add_plugin(plugin)
52
+ _plugins.push(plugin)
53
+ _around_stack.push { |subject, *args|
54
+ plugin.around(subject, *args) {
55
+ perform_block
56
+ }
57
+ }
58
+ end
59
+
60
+ def _load(plugin, &block)
61
+ if plugin
62
+ _load_plugin(plugin)
63
+ elsif block_given?
64
+ Plugin.create(&block)
65
+ else
66
+ raise Errors::LoadError, 'No plugin information provided'
67
+ end
68
+ end
69
+
70
+ def _load_plugin(plugin)
71
+ case plugin
72
+ when Class
73
+ plugin < Plugin && plugin or
74
+ raise Errors::LoadError, "Invalid plugin class: #{plugin.inspect} Must extend Plugin."
75
+ when Symbol, String
76
+ _load_plugin_by_name(plugin)
77
+ when Proc
78
+ Plugin.create(&plugin)
79
+ else
80
+ raise Errors::LoadError, "Invalid plugin identifier: #{plugin.inspect}"
81
+ end
82
+ end
83
+
84
+ def _load_plugin_by_name(name)
85
+ @_plugin_module && @_plugin_module.const_get("#{name.upcase}Plugin") or
86
+ raise Errors::LoadError, "Cannot load plugin by name. No plugin module provided."
87
+ end
88
+ end # Plugins
89
+ end # Ribbon
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ribbon-plugins
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Robert Honer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '3.2'
20
+ - - '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 3.2.0
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '3.2'
30
+ - - '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 3.2.0
33
+ description: A flexible plugins framework.
34
+ email:
35
+ - robert@ribbonpayments.com
36
+ executables: []
37
+ extensions: []
38
+ extra_rdoc_files: []
39
+ files:
40
+ - lib/ribbon/plugins.rb
41
+ - lib/ribbon/plugins/around_stack.rb
42
+ - lib/ribbon/plugins/block_stack.rb
43
+ - lib/ribbon/plugins/errors.rb
44
+ - lib/ribbon/plugins/plugin.rb
45
+ - lib/ribbon/plugins/version.rb
46
+ homepage: http://github.com/ribbon/plugins
47
+ licenses:
48
+ - BSD
49
+ metadata: {}
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubyforge_project:
66
+ rubygems_version: 2.2.2
67
+ signing_key:
68
+ specification_version: 4
69
+ summary: A flexible plugins framework.
70
+ test_files: []