mushroom 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mushroom.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,30 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ mushroom (0.0.1)
5
+ activesupport (>= 3.0.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activesupport (3.2.3)
11
+ i18n (~> 0.6)
12
+ multi_json (~> 1.0)
13
+ diff-lcs (1.1.3)
14
+ i18n (0.6.0)
15
+ multi_json (1.3.2)
16
+ rspec (2.9.0)
17
+ rspec-core (~> 2.9.0)
18
+ rspec-expectations (~> 2.9.0)
19
+ rspec-mocks (~> 2.9.0)
20
+ rspec-core (2.9.0)
21
+ rspec-expectations (2.9.1)
22
+ diff-lcs (~> 1.1.3)
23
+ rspec-mocks (2.9.0)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ mushroom!
30
+ rspec (>= 2.8.0)
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Ivan Vanderbyl
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # Mushroom
2
+
3
+ Mushroom is a super simple wrapper around ActiveSupport Instrumentation introduced in Rails 3.
4
+
5
+ Muchroom allows any component of your application to trigger events which later get subscribed to by any
6
+ other component in your application.
7
+
8
+ The returned event can be used to handle follow up behaviour, profile running code, and event dispatch requests to
9
+ other services.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'mushroom'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install mushroom
24
+
25
+ ## Usage
26
+
27
+ ```ruby
28
+
29
+ # app/models/server.rb
30
+ class Server
31
+ include Mushroom
32
+
33
+ def run
34
+ notify :start #=> Dispatches a 'server:start' event with the current server instance as the event target.
35
+ end
36
+
37
+ # You can instrument methods inline.
38
+ # This will trigger the server:stop event when you call #stop
39
+ # and notify all subscribers to the stop event.
40
+ #
41
+ # The server:stop event #duration will be 1 second.
42
+ #
43
+ def stop
44
+ sleep 1
45
+ end
46
+ instrument :stop
47
+ end
48
+
49
+ # lib/my\_app/event\_handler.rb
50
+ class EventHandler < Muchroom::Subscriber
51
+ events :start, :stop, :on => Server
52
+ events :cleanup, :on => ServerCache
53
+
54
+ def notify
55
+ # Handle event here
56
+ puts name #=> "server:start"
57
+ puts target #=> <Server id:1 ...>
58
+ puts duration #=> 0.001
59
+ end
60
+ end
61
+
62
+ Server.new.run
63
+ ```
64
+
65
+ ## Contributing
66
+
67
+ 1. Fork it
68
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
69
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
70
+ 4. Push to the branch (`git push origin my-new-feature`)
71
+ 5. Create new Pull Request
72
+
73
+ # Author
74
+
75
+ - Ivan Vanderbyl
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ $: << 'lib'
5
+
6
+ require "mushroom"
7
+ require 'rake'
8
+ require "rspec/core/rake_task"
9
+
10
+ desc "Run all examples"
11
+ RSpec::Core::RakeTask.new
12
+
13
+ task :default => :spec
14
+
data/lib/mushroom.rb ADDED
@@ -0,0 +1,55 @@
1
+ require 'mushroom/version'
2
+ require 'active_support'
3
+ require 'active_support/core_ext/array/extract_options'
4
+ require 'active_support/core_ext/class/attribute'
5
+ require 'active_support/inflector'
6
+ require 'active_support/core_ext/module/delegation'
7
+ require 'active_support/core_ext/module/aliasing'
8
+
9
+ module Mushroom
10
+ extend ActiveSupport::Concern
11
+
12
+ autoload :Subscriber, 'mushroom/subscriber'
13
+
14
+ included do
15
+ class_eval do
16
+ # Public: Instrument a method call
17
+ #
18
+ # Example:
19
+ # def start
20
+ # # work hard here
21
+ # end
22
+ # instrument :start
23
+ #
24
+ def self.instrument(method, options = {})
25
+ define_method(:"#{method}_with_instrument") do |*args, &block|
26
+ instrument(method) do
27
+ send(:"#{method}_without_instrument", *args, &block)
28
+ end
29
+ end
30
+ alias_method_chain method, 'instrument'
31
+ end
32
+ end
33
+ end
34
+
35
+ class << self
36
+ def event_name(event, sender)
37
+ if sender.is_a?(String)
38
+ klass_name = sender
39
+ else
40
+ klass_name = sender.respond_to?(:ancestors) && sender.ancestors.first == sender ? sender.name : sender.class.name
41
+ end
42
+ [klass_name.demodulize.underscore.gsub('/', ':'), event.to_s].join(':')
43
+ end
44
+ end
45
+
46
+ def notify(event, *args)
47
+ instrument(event, *args) {}
48
+ end
49
+
50
+ def instrument(event, *args, &block)
51
+ event = Mushroom.event_name(event, self)
52
+ ActiveSupport::Notifications.instrument(event.to_s, :target => self, :args => args, &block)
53
+ end
54
+
55
+ end
@@ -0,0 +1,84 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+ require 'active_support/core_ext/hash/slice'
3
+
4
+ module Mushroom
5
+ class Subscriber
6
+
7
+ attr_reader :event
8
+ delegate :payload, :name, :time, :transaction_id, :duration, :to => :event
9
+
10
+ def initialize(event)
11
+ @event = event
12
+ end
13
+
14
+ class << self
15
+
16
+ # Public: Setter and getter for events
17
+ #
18
+ # Can be called multiple times to set events on a Subscriber.
19
+ #
20
+ # Events cannot be inherited by subclassed objects.
21
+ #
22
+ # Example:
23
+ # class Handler < Mushroom::Subscriber
24
+ # events :start, :on => Server
25
+ # events :stop, :on => [Server, Time]
26
+ # events :register, :activate, :on => [User]
27
+ # end
28
+ #
29
+ # Returns: Array of current event registrations.
30
+ def events(*events_and_options)
31
+ if events_and_options.empty?
32
+ self._events
33
+ else
34
+ create_event_subscription(*events_and_options)
35
+ end
36
+ end
37
+
38
+ # Internal: Trigger the notification within this subscriber
39
+ def notify(event)
40
+ instance = new(event)
41
+
42
+ if instance.method(:notify).arity == 0
43
+ instance.notify
44
+ elsif instance.method(:notify).arity > 0
45
+ instance.notify(*event.payload[:args])
46
+ end
47
+ end
48
+
49
+ protected
50
+
51
+ def _events
52
+ Thread.current[:"_events_#{object_id}"] ||= []
53
+ end
54
+
55
+ def _events=(hash)
56
+ Thread.current[:"_events_#{object_id}"] = []
57
+ end
58
+
59
+ def create_event_subscription(*events_and_options)
60
+ options = {
61
+ :on => nil
62
+ }.update(events_and_options.extract_options!)
63
+
64
+ targets = Array(options[:on]) || raise(ArgumentError, "Event subscription must include :on => Class")
65
+
66
+ targets.each do |target|
67
+ events_and_options.each do |event|
68
+ event = Mushroom.event_name(event, target)
69
+
70
+ # Actually subscribe the event
71
+ ActiveSupport::Notifications.subscribe(event) do |*args|
72
+ self.notify(ActiveSupport::Notifications::Event.new(*args))
73
+ end
74
+
75
+ (self._events ||=[]).push(event)
76
+ end
77
+ end
78
+
79
+ return self._events
80
+ end
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,3 @@
1
+ module Mushroom
2
+ VERSION = "0.0.1"
3
+ end
data/mushroom.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/mushroom/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Ivan Vanderbyl"]
6
+ gem.email = ["ivanvanderbyl@me.com"]
7
+ gem.description = %q{Super simple events and instrumentation within your ruby app}
8
+ gem.summary = gem.description
9
+ gem.homepage = "https://github.com/ivanvanderbyl/mushroom"
10
+
11
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ gem.files = `git ls-files`.split("\n")
13
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ gem.name = "mushroom"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Mushroom::VERSION
17
+
18
+ gem.add_dependency "activesupport", ">= 3.0.0"
19
+
20
+ gem.add_development_dependency "rspec", ">= 2.8.0"
21
+ end
@@ -0,0 +1,101 @@
1
+ require "spec_helper"
2
+
3
+ describe Mushroom::Subscriber do
4
+
5
+ class Server
6
+ end
7
+
8
+ class Dummy
9
+ end
10
+
11
+ class EventHandler < Mushroom::Subscriber
12
+ def notify
13
+ end
14
+ end
15
+
16
+ class ServerEventHandler < Mushroom::Subscriber
17
+ def notify
18
+ end
19
+ end
20
+
21
+ after do
22
+ EventHandler.send(:_events=, {})
23
+ end
24
+
25
+ describe '.events' do
26
+ it 'allows adding event for a class' do
27
+ lambda { EventHandler.events :destroy, :on => Server }.should_not raise_error
28
+ EventHandler.events.should == ['server:destroy']
29
+ end
30
+
31
+ it 'stores events which weve added' do
32
+ EventHandler.events :start, :stop, :on => Server
33
+ EventHandler.events.should == ['server:start', 'server:stop']
34
+ end
35
+
36
+ it 'allows adding events for the same target multiple times' do
37
+ EventHandler.events :start, :on => Server
38
+ EventHandler.events :stop, :on => Server
39
+ EventHandler.events.should == ['server:start', 'server:stop']
40
+ end
41
+
42
+ it 'allows subscribing the same events to multiple targets' do
43
+ EventHandler.events :start, :on => [Server, Dummy]
44
+ EventHandler.events.should == ['server:start', 'dummy:start']
45
+ end
46
+
47
+ it 'does not inherit events across subscribers' do
48
+ EventHandler.send(:_events=, {})
49
+ EventHandler.events :stop, :on => Dummy
50
+ ServerEventHandler.events.should == []
51
+ ServerEventHandler.events :start, :on => Server
52
+ EventHandler.events.should == ['dummy:stop']
53
+ end
54
+
55
+ it 'should be thread safe' do
56
+ t1 = Thread.new { EventHandler.events :start, :on => Server }
57
+ t1.join
58
+ EventHandler.events.should == []
59
+ end
60
+ end
61
+
62
+ describe '.notify' do
63
+ it 'gets called when an event is triggered' do
64
+ class CustomHandler < Mushroom::Subscriber
65
+ events :start, :on => Server
66
+ end
67
+ CustomHandler.should_receive(:notify).once
68
+ Server.new.notify(:start)
69
+ end
70
+
71
+ it 'passes arguments to subscriber' do
72
+ class CustomHandler < Mushroom::Subscriber
73
+ events :start, :on => Server
74
+
75
+ def notify(payload)
76
+ payload.should == {:payload => {:id => 123}}
77
+ end
78
+ end
79
+
80
+ Server.new.notify(:start, {:payload => {:id => 123}})
81
+ end
82
+
83
+ it 'passes multiple arguments to subscriber' do
84
+ Thread.current[:now] = Time.now
85
+
86
+ class CustomHandler < Mushroom::Subscriber
87
+ events :start, :on => Server
88
+
89
+ def notify(payload, time)
90
+ payload.should == {:payload => {:id => 123}}
91
+ time.should_not == nil
92
+ time.should == Thread.current[:now]
93
+ end
94
+ end
95
+
96
+ Server.new.notify(:start, {:payload => {:id => 123}}, Thread.current[:now])
97
+ end
98
+
99
+ end
100
+ end
101
+
@@ -0,0 +1,57 @@
1
+ require "spec_helper"
2
+
3
+ describe Mushroom do
4
+ class Server
5
+ include Mushroom
6
+
7
+ def start
8
+ notify :start
9
+ end
10
+
11
+ def stop
12
+ sleep 0.1
13
+ end
14
+ instrument :stop
15
+ end
16
+
17
+ let(:server) { Server.new }
18
+
19
+ describe '.event_name' do
20
+ it 'constructs a valid event name from class and event triggered' do
21
+ server = Server.new
22
+
23
+ Mushroom.event_name(:start, server).should == 'server:start'
24
+ end
25
+
26
+ it 'works with a string' do
27
+ Mushroom.event_name(:start, 'server').should == 'server:start'
28
+ end
29
+
30
+ it 'works with a class' do
31
+ Mushroom.event_name(:start, Server).should == 'server:start'
32
+ end
33
+ end
34
+
35
+ describe 'Server' do
36
+ describe '#start' do
37
+ it 'triggers a server:start event' do
38
+ ActiveSupport::Notifications.should_receive(:instrument).with("server:start", {:target=>server, :args=>[]}).once
39
+ server.start
40
+ end
41
+ end
42
+
43
+ describe '#stop' do
44
+ it 'triggers a server:stop event' do
45
+ ActiveSupport::Notifications.should_receive(:instrument).with("server:stop", {:target=>server, :args=>[]}).once
46
+ server.stop
47
+ end
48
+ end
49
+ end
50
+
51
+ describe '#instrument' do
52
+ it 'can be called from instance' do
53
+ ActiveSupport::Notifications.should_receive(:instrument).with("server:render", {:target=>server, :args=>[]}).once
54
+ server.instrument(:render) { sleep 0.01 }
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,11 @@
1
+ require "mushroom"
2
+
3
+ Dir[File.expand_path("../support/*.rb", __FILE__)].each { |file| require file }
4
+
5
+ RSpec.configure do |config|
6
+ config.mock_with :rspec
7
+
8
+ config.before(:all) do
9
+ end
10
+ end
11
+
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mushroom
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ivan Vanderbyl
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: &70190744237180 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 3.0.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70190744237180
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &70190744236020 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 2.8.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70190744236020
36
+ description: Super simple events and instrumentation within your ruby app
37
+ email:
38
+ - ivanvanderbyl@me.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - .gitignore
44
+ - Gemfile
45
+ - Gemfile.lock
46
+ - LICENSE
47
+ - README.md
48
+ - Rakefile
49
+ - lib/mushroom.rb
50
+ - lib/mushroom/subscriber.rb
51
+ - lib/mushroom/version.rb
52
+ - mushroom.gemspec
53
+ - spec/mushroom/subscriber_spec.rb
54
+ - spec/mushroom_spec.rb
55
+ - spec/spec_helper.rb
56
+ homepage: https://github.com/ivanvanderbyl/mushroom
57
+ licenses: []
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 1.8.15
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: Super simple events and instrumentation within your ruby app
80
+ test_files:
81
+ - spec/mushroom/subscriber_spec.rb
82
+ - spec/mushroom_spec.rb
83
+ - spec/spec_helper.rb