Class: Utilisable::Service

Inherits:
Object
  • Object
show all
Defined in:
lib/utilisable/service.rb

Overview

Interface for running services - a place to move your business logic. Example: class TestService < ApplicationUtilities::Service

attr_reader :user_id

def initialize(user_id)
  @user_id = user_id
end

def call
  return broadcast(:fail) unless user_valid?

  do_some_stuff
  book = user.books.last
  user.delete
  broadcast(:ok, book)
end

private

def user_valid?
  user.name == 'Kyle'
end

def do_some_stuff
  #..more_code_here..
end

def user
  @user ||= User.find_by(id: user_id)
end

end

TestService.call(@user.id) # will delete user and won't affect 'broadcast' method

TestService.call(@user.id) do |obj|

obj.on(:fail) { raise 'Some error' }
obj.on(:ok) { |book|  @book = book }

end

@user.update(name: 'Stan') TestService.call(@user.id) do |obj|

obj.on(:fail) { raise 'Some error' }
obj.on(:ok) { |book|  @book = book }

end # 'Some error' will be raised

Some code here is commented - it is needed in order not to write 'obj.on' for setting listeners, and writing only 'on'. But this approach encapsulates listener blocks from controllers where they being called. It may be a good thing, but I found it irritating. Current approach allows us to return objects from service via broadcasts, which might be helpful.

Direct Known Subclasses

BackgroundService

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Service

Returns a new instance of Service.


70
# File 'lib/utilisable/service.rb', line 70

def initialize(*args); end

Class Method Details

.call(*args) {|obj| ... } ⇒ Object

Yields:

  • (obj)

60
61
62
63
64
65
66
67
68
# File 'lib/utilisable/service.rb', line 60

def self.call(*args)
  obj = new(*args)
  # obj.evaluate(&block) if block_given?
  yield obj if block_given?
  obj.call

  # obj.call_registrations
  # nil
end

Instance Method Details

#broadcast(name, *args) ⇒ Object


72
73
74
75
76
77
78
79
80
81
# File 'lib/utilisable/service.rb', line 72

def broadcast(name, *args)
  # TODO: add global listeners
  local_registrations.select { |registration| registration.name == name }.first&.broadcast(*args)
  self
  # registration = local_registrations.find { |registration| registration.name == name }
  # return if registration.nil?
  #
  # registration.arguments = *args
  # self
end

#callObject

Raises:

  • (NoMethodError)

105
106
107
# File 'lib/utilisable/service.rb', line 105

def call
  raise NoMethodError
end

#local_registrationsObject

def call_registrations

local_registrations.select { |registration| !registration.arguments.nil? }.each(&:broadcast)

end

def evaluate(&block)

@caller = eval('self', block.binding, __FILE__, __LINE__)
instance_eval(&block)

end


101
102
103
# File 'lib/utilisable/service.rb', line 101

def local_registrations
  @local_registrations ||= Set.new
end

#on(name, &block) ⇒ Object


87
88
89
90
# File 'lib/utilisable/service.rb', line 87

def on(name, &block)
  local_registrations << BlockRegistration.new(name, block)
  self
end

#transaction(&block) ⇒ Object


83
84
85
# File 'lib/utilisable/service.rb', line 83

def transaction(&block)
  ActiveRecord::Base.transaction(&block) if block_given?
end