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 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
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.2.2
5
+ before_install: gem install bundler -v 1.13.1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in use_case_pattern.gemspec
4
+ gemspec
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
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
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,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -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
@@ -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,3 @@
1
+ module UseCasePattern
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,8 @@
1
+ require "use_case_pattern/version"
2
+ require "use_case_pattern/base"
3
+
4
+ module UseCasePattern
5
+ def self.included(receiver)
6
+ receiver.send :include, UseCasePattern::Base
7
+ end
8
+ 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: []