use_case_pattern 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/README.md +74 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/export_to_redis.rb +31 -0
- data/examples/harvest.rb +67 -0
- data/examples/thing_speak_reporter.rb +32 -0
- data/lib/use_case_pattern/base.rb +44 -0
- data/lib/use_case_pattern/version.rb +3 -0
- data/lib/use_case_pattern.rb +8 -0
- data/use_case_pattern.gemspec +31 -0
- metadata +140 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a796de4be01c7ff1d29ac4b4a5be9cf14509f647
|
4
|
+
data.tar.gz: 95cbe71afd5dda0f93b6d537e2bbb782fbcab41a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4878b19038885f4654482ec655aaf340d931edb8a98d9ac280f7830adff2987c8f846981baaca2651b2e1db3121fadada88641ea19b46b02ab8f631877ef0978
|
7
|
+
data.tar.gz: f1e7b6b0ba605777cca19d621f89345aee70bf4135738b0ba2c7b28cba97b96a4d2021e0e843a40c557e61653110995cf3024b9581e2f1d2fbbcdbf0fc7fa499
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# UseCasePattern
|
2
|
+
|
3
|
+
A module that helps you to implement the Use Case design pattern.
|
4
|
+
|
5
|
+
This pattern is widely used by the teams at Abletech. We were first introduced to this pattern by Shevaun Coker at RubyConf AU 2015 in Melbourne, Australia. You can read more about this pattern in her blog post A [Case for Use Cases](http://webuild.envato.com/blog/a-case-for-use-cases/), and also in the [video of the presentation](https://rubyconf.eventer.com/rubyconf-australia-2015-1223/a-case-for-use-cases-by-shevaun-coker-1734) that she gave.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'use_case_pattern'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install use_case_pattern
|
22
|
+
|
23
|
+
## Basic Usage
|
24
|
+
|
25
|
+
When you follow the use case design pattern, you normally define a class with a constructor, and a perform method. You should include the `UseCasePattern` module. Here is a simple example:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
class NumberMultiplier
|
29
|
+
include UseCasePattern
|
30
|
+
|
31
|
+
attr_reader :product
|
32
|
+
|
33
|
+
validates :number1, :number2, presence: true
|
34
|
+
|
35
|
+
def initialize(number1, number2)
|
36
|
+
@number1 = number1
|
37
|
+
@number2 = number2
|
38
|
+
end
|
39
|
+
|
40
|
+
def perform
|
41
|
+
if valid?
|
42
|
+
@product = number1 * number2
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
attr_reader :number1, :number2
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
You could call this simple example from a Rails Controller, or anywhere else really. Here is an example:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
def multiply
|
56
|
+
multiplier = NumberMultiplier.perform(params[:number1], params[:number2])
|
57
|
+
|
58
|
+
if multiplier.success?
|
59
|
+
@result = multiplier.result
|
60
|
+
else
|
61
|
+
redirect_to :new, notice: multiplier.errors.full_messages
|
62
|
+
end
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
## Development
|
67
|
+
|
68
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
69
|
+
|
70
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
71
|
+
|
72
|
+
## Contributing
|
73
|
+
|
74
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/abletech/use_case_pattern.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "use_case_pattern"
|
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
|
data/bin/setup
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
class ExportToRedis
|
2
|
+
include UseCasePattern
|
3
|
+
|
4
|
+
validates :hit, presence: true
|
5
|
+
|
6
|
+
def initialize(hit:)
|
7
|
+
@hit = hit
|
8
|
+
end
|
9
|
+
|
10
|
+
def perform
|
11
|
+
redis.lpush("usage_hits", serialised_hit)
|
12
|
+
disconnect_redis
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_reader :hit
|
18
|
+
|
19
|
+
def redis
|
20
|
+
@redis ||= Redis.new(host: "127.0.0.1", port: 6379)
|
21
|
+
end
|
22
|
+
|
23
|
+
def disconnect_redis
|
24
|
+
redis.quit
|
25
|
+
@redis = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def serialised_hit
|
29
|
+
JSON.generate(hit.attributes)
|
30
|
+
end
|
31
|
+
end
|
data/examples/harvest.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
class Harvest
|
4
|
+
include UseCasePattern
|
5
|
+
|
6
|
+
def initialize(station_id:)
|
7
|
+
@station_id = station_id.to_i
|
8
|
+
end
|
9
|
+
|
10
|
+
def perform
|
11
|
+
run_query
|
12
|
+
parse_response
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :temperature, :wind_speed, :wind_direction, :wind_gust, :wind_compass, :recorded_at
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def parse_response
|
20
|
+
document = Nokogiri::HTML(@response_body)
|
21
|
+
|
22
|
+
@temperature = document.css('#temp').first.content.strip[0..-3]
|
23
|
+
@wind_speed = document.css('#windspd').first.content.strip.match(/[\d\.]+/)
|
24
|
+
@wind_direction = document.css('#windspd').first.content.strip.match(/Wind\s([NESW]+)\s.*/)[1]
|
25
|
+
@wind_gust = document.css('#windgust').first.content.strip.match(/Gust\s([\d\.]+)km\/h/)[1]
|
26
|
+
@recorded_at = Time.strptime(document.css('#title').first.content.strip, 'Weather at %H:%M %a %e %b %Y')
|
27
|
+
@wind_compass = case @wind_direction
|
28
|
+
when 'N' then 0
|
29
|
+
when 'NNE' then 23
|
30
|
+
when 'NE' then 45
|
31
|
+
when 'ENE' then 68
|
32
|
+
when 'E' then 90
|
33
|
+
when 'ESE' then 113
|
34
|
+
when 'SE' then 135
|
35
|
+
when 'SSE' then 158
|
36
|
+
when 'S' then 180
|
37
|
+
when 'SSW' then 203
|
38
|
+
when 'SW' then 225
|
39
|
+
when 'WSW' then 248
|
40
|
+
when 'W' then 270
|
41
|
+
when 'WNW' then 293
|
42
|
+
when 'NW' then 315
|
43
|
+
when 'NNW' then 338
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def host
|
48
|
+
'harvestelectronics.com'
|
49
|
+
end
|
50
|
+
|
51
|
+
def query_string
|
52
|
+
"/w.cgi?hsn=#{@station_id}&cmd=cwc"
|
53
|
+
end
|
54
|
+
|
55
|
+
def run_query
|
56
|
+
http = Net::HTTP.new(host)
|
57
|
+
response = http.request(Net::HTTP::Get.new(query_string))
|
58
|
+
|
59
|
+
if response.code != "200"
|
60
|
+
$stderr.puts "Harvest error (status-code: #{response.code})\n#{response.body}"
|
61
|
+
|
62
|
+
@response_body = nil
|
63
|
+
else
|
64
|
+
@response_body = response.body
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class ThingSpeakReporter
|
2
|
+
include UseCasePattern
|
3
|
+
|
4
|
+
def initialize(api_key:, params: {})
|
5
|
+
@api_key = api_key
|
6
|
+
@params = params
|
7
|
+
end
|
8
|
+
|
9
|
+
def perform
|
10
|
+
post_data
|
11
|
+
check_response
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
attr_reader :params, :api_key, :response
|
17
|
+
|
18
|
+
def post_data
|
19
|
+
uri = URI("https://api.thingspeak.com/update.json")
|
20
|
+
@response = Net::HTTP.post_form(uri, request_params)
|
21
|
+
end
|
22
|
+
|
23
|
+
def check_response
|
24
|
+
if response.code != '200'
|
25
|
+
errors.add(:base, "Non 200 response #{response.code}: #{response.body}")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def request_params
|
30
|
+
params.merge(api_key: api_key)
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "active_support"
|
2
|
+
require "active_model"
|
3
|
+
|
4
|
+
module UseCasePattern
|
5
|
+
module Base
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
include ActiveModel::Validations
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
# The perform method of a UseCase should always return itself
|
11
|
+
def perform(*args)
|
12
|
+
new(*args).tap { |use_case| use_case.perform }
|
13
|
+
end
|
14
|
+
|
15
|
+
# Raise an exception if perform generates any errors
|
16
|
+
def perform!(*args)
|
17
|
+
new(*args).tap { |use_case| use_case.perform! }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Implement all the steps required to complete this use case
|
22
|
+
def perform
|
23
|
+
raise NotImplementedError
|
24
|
+
end
|
25
|
+
|
26
|
+
def perform!
|
27
|
+
perform
|
28
|
+
|
29
|
+
if failure?
|
30
|
+
raise_validation_error
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Has this use case performed its task successfully?
|
35
|
+
def success?
|
36
|
+
errors.none?
|
37
|
+
end
|
38
|
+
|
39
|
+
# Did this use case have any errors?
|
40
|
+
def failure?
|
41
|
+
errors.any?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'use_case_pattern/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "use_case_pattern"
|
8
|
+
spec.version = UseCasePattern::VERSION
|
9
|
+
spec.authors = ["Nigel Ramsay"]
|
10
|
+
spec.email = ["nigel@abletech.nz"]
|
11
|
+
|
12
|
+
spec.summary = "A module that helps you to implement the Use Case design pattern"
|
13
|
+
spec.description = "A module that helps you to implement the Use Case design pattern"
|
14
|
+
spec.homepage = "https://github.com/abletech/use_case_pattern"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.required_ruby_version = '~> 2.0'
|
24
|
+
|
25
|
+
spec.add_runtime_dependency "activemodel", [">= 4.0.0", "~> 5.0.0"]
|
26
|
+
spec.add_runtime_dependency "activesupport", [">= 4.0.0", "~> 5.0.0"]
|
27
|
+
|
28
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
29
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
30
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: use_case_pattern
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nigel Ramsay
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-09-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activemodel
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 4.0.0
|
20
|
+
- - "~>"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 5.0.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 4.0.0
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 5.0.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: activesupport
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 4.0.0
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 5.0.0
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 4.0.0
|
50
|
+
- - "~>"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 5.0.0
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: bundler
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '1.13'
|
60
|
+
type: :development
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - "~>"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '1.13'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: rake
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '10.0'
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '10.0'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: rspec
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - "~>"
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '3.0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - "~>"
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '3.0'
|
95
|
+
description: A module that helps you to implement the Use Case design pattern
|
96
|
+
email:
|
97
|
+
- nigel@abletech.nz
|
98
|
+
executables: []
|
99
|
+
extensions: []
|
100
|
+
extra_rdoc_files: []
|
101
|
+
files:
|
102
|
+
- ".gitignore"
|
103
|
+
- ".rspec"
|
104
|
+
- ".travis.yml"
|
105
|
+
- Gemfile
|
106
|
+
- README.md
|
107
|
+
- Rakefile
|
108
|
+
- bin/console
|
109
|
+
- bin/setup
|
110
|
+
- examples/export_to_redis.rb
|
111
|
+
- examples/harvest.rb
|
112
|
+
- examples/thing_speak_reporter.rb
|
113
|
+
- lib/use_case_pattern.rb
|
114
|
+
- lib/use_case_pattern/base.rb
|
115
|
+
- lib/use_case_pattern/version.rb
|
116
|
+
- use_case_pattern.gemspec
|
117
|
+
homepage: https://github.com/abletech/use_case_pattern
|
118
|
+
licenses: []
|
119
|
+
metadata: {}
|
120
|
+
post_install_message:
|
121
|
+
rdoc_options: []
|
122
|
+
require_paths:
|
123
|
+
- lib
|
124
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - "~>"
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '2.0'
|
129
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
requirements: []
|
135
|
+
rubyforge_project:
|
136
|
+
rubygems_version: 2.4.8
|
137
|
+
signing_key:
|
138
|
+
specification_version: 4
|
139
|
+
summary: A module that helps you to implement the Use Case design pattern
|
140
|
+
test_files: []
|