All Projects → umbrellio → polist

umbrellio / polist

Licence: MIT license
Ruby gem for creating simple service classes.

Programming Languages

ruby
36898 projects - #4 most used programming language

Projects that are alternatives of or similar to polist

firewall-controller
A kubernetes controller running on bare-metal firewalls, creating nftables rules, configures suricata, collects network metrics
Stars: ✭ 37 (+105.56%)
Mutual labels:  services
ghi
GitHub IRC Notification Service
Stars: ✭ 26 (+44.44%)
Mutual labels:  services
cim-spec
This repository hosts the specification for the Cartographic Information Model
Stars: ✭ 45 (+150%)
Mutual labels:  services
platform
A collection of minimalistic, easy-to-use and fully customizable Angular components, directives and services
Stars: ✭ 17 (-5.56%)
Mutual labels:  services
daikon
Common modules shared by Talend applications
Stars: ✭ 14 (-22.22%)
Mutual labels:  services
ember-browser-services
Services for interacting with browser APIs so that you can have fine-grained control in tests.
Stars: ✭ 44 (+144.44%)
Mutual labels:  services
mezon
Mezon is a simple php framework wich will help you to create business applications.
Stars: ✭ 35 (+94.44%)
Mutual labels:  services
docker-compose-collection
These docker-compose allow you to deploy multiple services easily and quickly. You can use them with Portainer directly or via docker-compose commands.
Stars: ✭ 37 (+105.56%)
Mutual labels:  services
awesome-hosting
List of awesome hosting
Stars: ✭ 134 (+644.44%)
Mutual labels:  services
out
Monitor services in your menu bar
Stars: ✭ 155 (+761.11%)
Mutual labels:  services
flutter plugin appcenter
Flutter plugins for accessing Visual Studio App Center services.
Stars: ✭ 55 (+205.56%)
Mutual labels:  services
Functor
Mappable objects
Stars: ✭ 20 (+11.11%)
Mutual labels:  functional-objects
act-form
The simple way to create form objects or command/service objects with ActiveModel
Stars: ✭ 29 (+61.11%)
Mutual labels:  service-object
balance
Client side load balancing for Kubernetes clusters
Stars: ✭ 18 (+0%)
Mutual labels:  services
porter
Export legacy forums into a format Vanilla Forums can import.
Stars: ✭ 39 (+116.67%)
Mutual labels:  services
interactor
Simple service objects for PHP
Stars: ✭ 36 (+100%)
Mutual labels:  service-object
operators-service
Service Object based on Either Monad
Stars: ✭ 27 (+50%)
Mutual labels:  service-object
Nano.Library
Take full advantage of Nano Library, and rapidly implement enriched .Net 6.0 micro-services.
Stars: ✭ 39 (+116.67%)
Mutual labels:  services
overview-broker
A service broker that provides an overview of its service instances and bindings. Conforms to the Open Service Broker API standard.
Stars: ✭ 18 (+0%)
Mutual labels:  services
examples
Code examples you can use with Horizon.
Stars: ✭ 33 (+83.33%)
Mutual labels:  services

Polist   Gem Version Build Status Coverage Status

DEPRECATION NOTICE

This gem is no longer actively maintained. As a replacement, you can use Resol as well as gems from smart-rb family.

Description

Polist is a set of simple tools for creating business logic layer of your applications:

  • Polist::Service is a simple class designed for creating service classes.
  • Polist::Builder is a builder system based on Uber::Builder.
  • Polist::Struct is a small utility that helps generating simple Struct-like object initializers.

Installation

Simply add gem "polist" to your Gemfile.

Using Polist::Service

class MyService < Polist::Service
  def call
    if params[:ok]
      success!(code: :cool)
    else
      fail!(code: :not_cool)
    end
  end
end

service = MyService.run(ok: true)
service.success? #=> true
service.response #=> { code: :cool }

service = MyService.run(ok: false)
service.success? #=> false
service.response #=> { code: :not_cool }

The only parameter that is passed to the service is called params by default. If you want more params, feel free to define your own initializer and call the service accordingly:

class MyService < Polist::Service
  def initialize(a, b, c)
    # ...
  end
end

MyService.call(1, 2, 3)

Unlike .run, .call will raise Polist::Service::Failure exception on failure:

begin
  MyService.call(ok: false)
rescue Polist::Service::Failure => error
  error.response #=> { code: :not_cool }
end

Note that .run and .call are just shortcuts for MyService.new(...).run and MyService.new(...).call with the only difference that they always return the service instance instead of the result of #run or #call. Unlike #call though, #run is not intended to be overwritten in subclasses.

Using blocks in #call and #run methods.

You can use yield in #call. And then call ::run or ::call class methods with block. For example, we have the class:

class BlockFun < Polist::Service
  def call
    success!(yield(1, 2))
  end
end

Then we can use it like this:

service = BlockFun.call { |a, b| a + b }

p service.response # => 3

Behind the scenes it just catches passed block in class methods ::run and ::call, converts it to proc and then passes proc to instance method #call and #run by converting it back to block. So, for example, if you want to pass this block to private methods, you can write code like this:

class AnotherBlockFun < Polist::Service
  def call(&block)
    success!(block_caller(&block))
  end

  private

  def block_caller
    yield 1, 2
  end
end

service = AnotherBlockFun.call { |a, b| a + b }

p service.response # => 3

Using Form objects

Sometimes you want to use some kind of params parsing and/or validation, and you can do that with the help of Polist::Service::Form class. It uses tainbox gem under the hood.

class MyService < Polist::Service
  class Form < Polist::Service::Form
    attribute :param1, :String
    attribute :param2, :Integer
    attribute :param3, :String, default: "smth"
    attribute :param4, :String

    validates :param4, presence: true
  end

  def call
    p form.valid?
    p [form.param1, form.param2, form.param3]
  end

  # The commented code is just the default implementation and can be simply overwritten
  # private

  # def form
  #   @form ||= self.class::Form.new(form_attributes.to_snake_keys)
  # end

  # def form_attributes
  #   params
  # end
end

MyService.call(param1: "1", param2: "2") # prints false and then ["1", 2, "smth"]

The #form method is there just for convinience and by default it uses what #form_attributes returns as the attributes for the default form class which is the services' Form class. You are free to use as many different form classes as you want in your service.

Using Polist::Builder

The build logic is based on Uber::Builder but it allows recursive builders. See the example:

Can be used with Polist::Service or any other Ruby class.

class User
  include Polist::Builder

  builds do |role|
    case role
    when /admin/
      Admin
    end
  end

  attr_accessor :role

  def initialize(role)
    self.role = role
  end
end

class Admin < User
  builds do |role|
    SuperAdmin if role == "super_admin"
  end

  class SuperAdmin < Admin
    def super?
      true
    end
  end

  def super?
    false
  end
end

User.build("user") # => #<User:... @role="user">

User.build("admin") # => #<Admin:... @role="admin">
User.build("admin").super? # => false

User.build("super_admin") # => #<Admin::SuperAdmin:... @role="super_admin">
User.build("super_admin").super? # => true

Admin.build("smth") # => #<Admin:... @role="admin">
SuperAdmin.build("smth") # => #<Admin::SuperAdmin:... @role="admin">

Using Polist::Struct

Works pretty much the same like Ruby Struct class, but you don't have to subclass it.

Can be used with Polist::Service or any other class that don't have initializer specified.

class Point
  include Polist::Struct

  struct :x, :y
end

a = Point.new(15, 25)
a.x # => 15
a.y # => 25

b = Point.new(15, 25, 35) # raises ArgumentError: struct size differs

c = Point.new(15)
c.x # => 15
c.y # => nil

Using Middlewares

If you have some common things to be done in more than one service, you can define a middleware and register it inside the said services. Every middleware takes the service into it's constructor and executes #call. Thus every middleware has to implement #call method and has a #service attribute reader. Middlewares delegate #success!, #fail!, #error!, #form, #form_attributes to the service class they are registered in. Every middleware should be a subclass of Polist::Service::Middleware. Middlewares are run before the service itself is run.

To register a middleware one should use .register_middleware class method on a service. More than one middleware can be registered for one service.

For example:

class MyMiddleware < Polist::Service::Middleware
  def call
    fail!(code: :not_cool) if service.fail_on_middleware?
  end
end

class MyService < Polist::Service
  register_middleware MyMiddleware

  def call
    success!(code: :cool)
  end

  def fail_on_middleware?
    true
  end
end

service = MyService.run
service.success? #=> false
service.response #=> { code: :not_cool }

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/umbrellio/polist.

License

Released under MIT License.

Authors

Created by Yuri Smirnov.

Supported by Umbrellio
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].