homie 0.1.1
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 +7 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +127 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/homie.gemspec +27 -0
- data/lib/homie/version.rb +3 -0
- data/lib/homie.rb +48 -0
- metadata +98 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 02a83ffb1ca07691cc5e4563232c6b7fcf2b37301b6d25e49802da9d00a05e53
|
|
4
|
+
data.tar.gz: e38bc97637559253ed94e228bfd24b107e597f1b5be4c21ebac65752bb157eb7
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 4d1eb81b22defd2e978d9c52e9f228b230859fd8e4451c746052f495bc7070644c3d1fb6c90f39705349b08931631cba9bdc75cf8ebe631ad04fd7a903705405
|
|
7
|
+
data.tar.gz: 6683f0fe3467c0cbedd4b81a186bb3764406e38bef3628b6bbf670c9b62c64fb8f5a09f7e13b917994bde1a7217951e629c09da83e7d79b8327635a61251a161
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 donasktello
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Homie
|
|
2
|
+
|
|
3
|
+
Welcome!
|
|
4
|
+
|
|
5
|
+
Those of you who know why and when we need the Observer pattern will definitely find this gem useful. Those of you who don't, should read about the Observer pattern and return here afterward.
|
|
6
|
+
|
|
7
|
+
Ruby has a default module called Observable that reflect same idea but doesn't have such flexibility as Homie.
|
|
8
|
+
|
|
9
|
+
Homie will do the dirty work for you. It will call and execute all required logic sequentially. All you need is to:
|
|
10
|
+
|
|
11
|
+
- consider Homie syntax
|
|
12
|
+
- decompose the logic into the `subject` and `observers` bound to particular events
|
|
13
|
+
- broadcast those events when they happen
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
Add this line to your application's Gemfile:
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
gem 'homie'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
And then execute:
|
|
24
|
+
|
|
25
|
+
$ bundle
|
|
26
|
+
|
|
27
|
+
Or install it yourself as:
|
|
28
|
+
|
|
29
|
+
$ gem install homie
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
### About
|
|
33
|
+
To implement Observer pattern and start using Homie first you should decompose logic into 2 object types:
|
|
34
|
+
* `Subject` - the main part of logic, depending on the results of which the further part of logic should vary between scenarios.
|
|
35
|
+
* `Observer` - those scenarios that will be executed depending on the Subject result.
|
|
36
|
+
|
|
37
|
+
### Include into your `Subject` Homie module
|
|
38
|
+
|
|
39
|
+
```ruby
|
|
40
|
+
include Homie
|
|
41
|
+
```
|
|
42
|
+
### Subscribing
|
|
43
|
+
|
|
44
|
+
Bind `Observers` to your `Subject` on particular events. As an `Observer` it could be any object with a *call* method(that is an entry point for business logic) **OR** a block of code.
|
|
45
|
+
|
|
46
|
+
To bind Observer use method `on(event_name, Observer)`.
|
|
47
|
+
|
|
48
|
+
You have 2 options, how you could bind your observers:
|
|
49
|
+
|
|
50
|
+
* When you want to incapsulate those observers.
|
|
51
|
+
```ruby
|
|
52
|
+
class UserCreator
|
|
53
|
+
include Homie
|
|
54
|
+
|
|
55
|
+
def initialize(params)
|
|
56
|
+
@params = params
|
|
57
|
+
|
|
58
|
+
self.on(:succeeded, StatistictsGenerator.new)
|
|
59
|
+
self.on(:succeeded) { |user| EmailPublisher.send_email(user) }
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
*Your observers should repeat signature of params passing by Subject in their method call or in a block of code.*
|
|
65
|
+
|
|
66
|
+
* When incapsulation don't bother you **OR** you need to apply a closure for some context/method execution.
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
class UsersController < ApplicationController
|
|
70
|
+
def create
|
|
71
|
+
UserCreator.new(params).
|
|
72
|
+
on(:succeeded) do |user|
|
|
73
|
+
render json: user, status: 201
|
|
74
|
+
end.
|
|
75
|
+
on(:failed) do |user|
|
|
76
|
+
render json: user.errors, status: 422
|
|
77
|
+
end.call
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
*Subscribing supports chaining*.
|
|
83
|
+
|
|
84
|
+
### Broadcasting
|
|
85
|
+
To broadcast an event use method `broadcast(event_name, *arguments)`.
|
|
86
|
+
*Broadcasting also support chaining.*
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
class UserCreator
|
|
90
|
+
include Homie
|
|
91
|
+
|
|
92
|
+
def initialize(params)
|
|
93
|
+
@params = params
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def call
|
|
97
|
+
user = User.create!(@params)
|
|
98
|
+
broadcast :succeeded, user
|
|
99
|
+
rescue ActiveRecord::RecordInvalid => invalid
|
|
100
|
+
broadcast :failed, invalid.record
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
*You can incapsulate broadcasting of events or make public method calls as well.*
|
|
106
|
+
|
|
107
|
+
I support the theory that says that two events are usually enough: **succeeded** or **failed**.
|
|
108
|
+
|
|
109
|
+
I have made shortcuts for these cases.
|
|
110
|
+
|
|
111
|
+
So
|
|
112
|
+
|
|
113
|
+
`broadcast :succeeded, user` is equal to `succeeded(user)`
|
|
114
|
+
|
|
115
|
+
**and**
|
|
116
|
+
|
|
117
|
+
`broadcast :failed, user` is equal to `failed(user)`.
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
## Contributing
|
|
121
|
+
|
|
122
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/donasktello/homie. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
|
123
|
+
|
|
124
|
+
## License
|
|
125
|
+
|
|
126
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
|
127
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "homie"
|
|
5
|
+
|
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
8
|
+
|
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
+
# require "pry"
|
|
11
|
+
# Pry.start
|
|
12
|
+
|
|
13
|
+
require "irb"
|
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/homie.gemspec
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'homie/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "homie"
|
|
8
|
+
spec.version = Homie::VERSION
|
|
9
|
+
spec.authors = ["Viacheslav Shvetsov"]
|
|
10
|
+
spec.email = ["shvetsov1988@gmail.com"]
|
|
11
|
+
|
|
12
|
+
spec.summary = %q{Implementation of Observer pattern with using objects or code blocks.}
|
|
13
|
+
spec.description = %q{Implementation of Observer pattern.}
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
spec.homepage = "https://github.com/donasktello/homie"
|
|
16
|
+
|
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
|
19
|
+
end
|
|
20
|
+
spec.bindir = "exe"
|
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
22
|
+
spec.require_paths = ["lib"]
|
|
23
|
+
|
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
|
27
|
+
end
|
data/lib/homie.rb
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require "homie/version"
|
|
2
|
+
|
|
3
|
+
module Homie
|
|
4
|
+
class ObserverNotPassedError < StandardError
|
|
5
|
+
MSG = 'You should pass at least one or more objects with method call OR block.'
|
|
6
|
+
|
|
7
|
+
def message; MSG end;
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class EventNotSpecifiedError < StandardError
|
|
11
|
+
MSG = 'You should specify event name.'
|
|
12
|
+
|
|
13
|
+
def message; MSG end;
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def on(event, *objects, &block)
|
|
17
|
+
raise(Homie::EventNotSpecifiedError) unless event && !event.empty?
|
|
18
|
+
|
|
19
|
+
raise(Homie::ObserverNotPassedError) unless objects.all? { |object| object.respond_to?(:call) }
|
|
20
|
+
|
|
21
|
+
raise(Homie::ObserverNotPassedError) if (_observers = [*objects, block].compact).size == 0
|
|
22
|
+
|
|
23
|
+
observers[event] += _observers
|
|
24
|
+
|
|
25
|
+
self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def broadcast(event, *args)
|
|
29
|
+
observers[event].each { |observer| observer.call(*args) }
|
|
30
|
+
|
|
31
|
+
self
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def succeeded(*args)
|
|
35
|
+
broadcast(:succeeded, *args)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def failed(*args)
|
|
39
|
+
broadcast(:failed, *args)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def observers
|
|
45
|
+
@observers ||= Hash.new { |hash, event| hash[event] = [] }
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
metadata
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: homie
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Viacheslav Shvetsov
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2018-06-29 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.14'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.14'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '10.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '10.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rspec
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '3.0'
|
|
55
|
+
description: Implementation of Observer pattern.
|
|
56
|
+
email:
|
|
57
|
+
- shvetsov1988@gmail.com
|
|
58
|
+
executables: []
|
|
59
|
+
extensions: []
|
|
60
|
+
extra_rdoc_files: []
|
|
61
|
+
files:
|
|
62
|
+
- ".gitignore"
|
|
63
|
+
- ".rspec"
|
|
64
|
+
- ".travis.yml"
|
|
65
|
+
- Gemfile
|
|
66
|
+
- LICENSE.txt
|
|
67
|
+
- README.md
|
|
68
|
+
- Rakefile
|
|
69
|
+
- bin/console
|
|
70
|
+
- bin/setup
|
|
71
|
+
- homie.gemspec
|
|
72
|
+
- lib/homie.rb
|
|
73
|
+
- lib/homie/version.rb
|
|
74
|
+
homepage: https://github.com/donasktello/homie
|
|
75
|
+
licenses:
|
|
76
|
+
- MIT
|
|
77
|
+
metadata: {}
|
|
78
|
+
post_install_message:
|
|
79
|
+
rdoc_options: []
|
|
80
|
+
require_paths:
|
|
81
|
+
- lib
|
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
83
|
+
requirements:
|
|
84
|
+
- - ">="
|
|
85
|
+
- !ruby/object:Gem::Version
|
|
86
|
+
version: '0'
|
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
88
|
+
requirements:
|
|
89
|
+
- - ">="
|
|
90
|
+
- !ruby/object:Gem::Version
|
|
91
|
+
version: '0'
|
|
92
|
+
requirements: []
|
|
93
|
+
rubyforge_project:
|
|
94
|
+
rubygems_version: 2.7.7
|
|
95
|
+
signing_key:
|
|
96
|
+
specification_version: 4
|
|
97
|
+
summary: Implementation of Observer pattern with using objects or code blocks.
|
|
98
|
+
test_files: []
|