rails-patterns 0.1.1 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e7a4ed45fc0663789bf4ddb050d8d1a24dfb88af
4
- data.tar.gz: 5e4b2c49b8477c44764f611439f1d556d6e361b2
3
+ metadata.gz: e92ba62b5937443b24c3399655e678b6deb2d273
4
+ data.tar.gz: '0973bdde4d88392f6cd3a2a8a08fe77a3cf1f007'
5
5
  SHA512:
6
- metadata.gz: c2e27126c96ec9d5a508ccade1c3b11db7bfbeb7dc06c7754ac8ce154ae784800a5b0bd2be9b69fb74e19855c65e5dfe95defd3f46199a5b694b4cb7082a8a5a
7
- data.tar.gz: 047f3867ed52a6a7cbad689ea8be6fff248d3acb6ead8a9abf93b9ce7ef57379aa312a351ddfe417302fd63f54c0bb6fbb415a425a0f54025bad9ab8a8866e75
6
+ metadata.gz: 8fd3b635495855827654b7b818ee074ac562a919e6610c470cce226afcdf0dfe9944ff5867858d945054732c503babd63588d3775c517f9270846901f56eeb00
7
+ data.tar.gz: '068e1a602e2e1c591853e1491cfb1bf13e48f56dbaff45ee0db72417be176036939073769212d983da7b098ca5ecccd6935b0812fd83f761ee7db9cd176488e0'
data/README.md CHANGED
@@ -71,3 +71,52 @@ class User < ApplicationRecord
71
71
  scope :recenty_activated, RecentlyActivatedUsersQuery
72
72
  end
73
73
  ```
74
+
75
+ ## Service
76
+
77
+ ### When to use it
78
+
79
+ Service objects are commonly used to mitigate problems with model callbacks that interact with external classes ([read more...](http://samuelmullen.com/2013/05/the-problem-with-rails-callbacks/)).
80
+ Service objects are also useful for handling processes involving multiple steps. E.g. a controller that performs more than one operation on its subject (usually a model instance) is a possible candidate for Extract ServiceObject (or Extract FormObject) refactoring.
81
+
82
+ ### Assumptions and rules
83
+
84
+ * Service objects are always used by calling class-level `.call` method
85
+ * Service objects have to implement `#call` method
86
+ * Calling service object's `.call` method executes `#call` and returns service object instance
87
+ * A result of `#call` method is accessible through `#result` method
88
+ * It is recommended for `#call` method to be the only public method of service object (besides state readers)
89
+ * It is recommended to name service object classes after commands (e.g. `ActivateUser` instead of `UserActivation`)
90
+
91
+ ### Examples
92
+
93
+ #### Declaration
94
+
95
+ ```ruby
96
+ class ActivateUser < Patterns::Service
97
+ def initialize(user)
98
+ @user = user
99
+ end
100
+
101
+ def call
102
+ user.activate!
103
+ NotificationsMailer.user_activation_notification(user).deliver_now
104
+ user
105
+ end
106
+
107
+ private
108
+
109
+ attr_reader :user
110
+ end
111
+ ```
112
+
113
+ #### Usage
114
+
115
+ ```ruby
116
+ user_activation = ActivateUser.call(user)
117
+ user_activation.result # <User id: 5803143, email: "tony@patterns.dev ...
118
+ ```
119
+
120
+ ## Further reading
121
+
122
+ * [7 ways to decompose fat active record models](http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.2.0
@@ -0,0 +1,18 @@
1
+ module Patterns
2
+ class Service
3
+ attr_reader :result
4
+
5
+ def self.call(*args)
6
+ new(*args).tap do |service|
7
+ service.instance_variable_set(
8
+ "@result",
9
+ service.call
10
+ )
11
+ end
12
+ end
13
+
14
+ def call
15
+ raise NotImplementedError
16
+ end
17
+ end
18
+ end
@@ -1,2 +1,3 @@
1
1
  require "patterns"
2
2
  require "patterns/query"
3
+ require "patterns/service"
@@ -2,11 +2,11 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: rails-patterns 0.1.1 ruby lib
5
+ # stub: rails-patterns 0.2.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "rails-patterns".freeze
9
- s.version = "0.1.1"
9
+ s.version = "0.2.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
@@ -29,9 +29,11 @@ Gem::Specification.new do |s|
29
29
  "VERSION",
30
30
  "lib/patterns.rb",
31
31
  "lib/patterns/query.rb",
32
+ "lib/patterns/service.rb",
32
33
  "lib/rails-patterns.rb",
33
34
  "rails-patterns.gemspec",
34
35
  "spec/patterns/query_spec.rb",
36
+ "spec/patterns/service_spec.rb",
35
37
  "spec/spec_helper.rb"
36
38
  ]
37
39
  s.homepage = "http://github.com/selleo/pattern".freeze
@@ -0,0 +1,65 @@
1
+ RSpec.describe Patterns::Service do
2
+ after { Object.send(:remove_const, :DoSomething) if defined?(DoSomething) }
3
+
4
+ describe ".call" do
5
+ it "returns instance of service object" do
6
+ DoSomething = Class.new(Patterns::Service) do
7
+ def call; end
8
+ end
9
+
10
+ expect(DoSomething.call).to be_kind_of(DoSomething)
11
+ end
12
+
13
+ it "instantiates service object passing arguments to constructor" do
14
+ DoSomething = Class.new(Patterns::Service) do
15
+ def initialize(argument_1:, argument_2:); end
16
+ def call; end
17
+ end
18
+
19
+ expect {
20
+ DoSomething.call
21
+ }.to raise_error ArgumentError
22
+
23
+ expect {
24
+ DoSomething.call(argument_1: 10, argument_2: 20)
25
+ }.not_to raise_error
26
+ end
27
+
28
+ it "calls #call method on service object instance" do
29
+ Spy = Class.new do
30
+ def self.some_method; end
31
+ end
32
+ allow(Spy).to receive(:some_method)
33
+ DoSomething = Class.new(Patterns::Service) do
34
+ def call
35
+ Spy.some_method
36
+ end
37
+ end
38
+
39
+ DoSomething.call
40
+
41
+ expect(Spy).to have_received(:some_method)
42
+ end
43
+
44
+ it "requires #call method to be implemented" do
45
+ DoSomething = Class.new(Patterns::Service)
46
+
47
+ expect {
48
+ DoSomething.call
49
+ }.to raise_error NotImplementedError
50
+ end
51
+ end
52
+
53
+ describe "#result" do
54
+ it "returns a result of expression within #call method" do
55
+ DoSomething = Class.new(Patterns::Service) do
56
+ def call
57
+ 50
58
+ end
59
+ end
60
+
61
+ service = DoSomething.call
62
+ expect(service.result).to eq 50
63
+ end
64
+ end
65
+ end
@@ -17,7 +17,7 @@
17
17
  #
18
18
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
19
19
 
20
- require "pattern"
20
+ require "rails-patterns"
21
21
 
22
22
  RSpec.configure do |config|
23
23
  # rspec-expectations config goes here. You can use an alternate
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-patterns
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stevo
@@ -84,9 +84,11 @@ files:
84
84
  - VERSION
85
85
  - lib/patterns.rb
86
86
  - lib/patterns/query.rb
87
+ - lib/patterns/service.rb
87
88
  - lib/rails-patterns.rb
88
89
  - rails-patterns.gemspec
89
90
  - spec/patterns/query_spec.rb
91
+ - spec/patterns/service_spec.rb
90
92
  - spec/spec_helper.rb
91
93
  homepage: http://github.com/selleo/pattern
92
94
  licenses: