{"id":15064575,"url":"https://github.com/umbrellio/verifly","last_synced_at":"2025-04-10T12:23:35.591Z","repository":{"id":56897332,"uuid":"86470217","full_name":"umbrellio/verifly","owner":"umbrellio","description":"This gem provides an api to run sequential checks","archived":false,"fork":false,"pushed_at":"2020-10-21T09:08:41.000Z","size":53,"stargazers_count":1,"open_issues_count":2,"forks_count":1,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-02-03T01:11:45.820Z","etag":null,"topics":["activemodel","rails","uber"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/umbrellio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-28T14:31:40.000Z","updated_at":"2020-10-21T09:08:43.000Z","dependencies_parsed_at":"2022-08-20T17:40:30.615Z","dependency_job_id":null,"html_url":"https://github.com/umbrellio/verifly","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/umbrellio%2Fverifly","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/umbrellio%2Fverifly/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/umbrellio%2Fverifly/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/umbrellio%2Fverifly/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/umbrellio","download_url":"https://codeload.github.com/umbrellio/verifly/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239241513,"owners_count":19605938,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activemodel","rails","uber"],"created_at":"2024-09-25T00:20:49.146Z","updated_at":"2025-02-17T05:31:29.050Z","avatar_url":"https://github.com/umbrellio.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Verifly v0.2\n[![Build Status](https://travis-ci.org/umbrellio/verifly.svg?branch=master)](https://travis-ci.org/umbrellio/verifly)[![Coverage Status](https://coveralls.io/repos/github/umbrellio/verifly/badge.svg)](https://coveralls.io/github/umbrellio/verifly)\n\nThis gem provides an api to run sequential checks like\n'ActiveModel::Validations' do, but with generic messages instead of errors.\n\nIt also provides additional components to build it which could be used\nto imporve code readability. See [Applicator](#Applicator),\n[ApplicatorWithOptions](#ApplicatorWithOptions) and\n[ClassBuilder](#ClassBuilder) along with [Verifier](#Verifier)\n\n## Instalation\n\n```\n$ gem install verifly\n```\n\nand then in code\n\n```\nrequire 'verifly'\n```\n\n## ClassBuilder\n\nexample:\n\n```lang=ruby\nAbstract = Struct.new(:data)\n  extend Verifly::ClassBuilder::Mixin\n\n  class WithString \u003c self\n    def self.build_class(x)\n      self if x.is_a?(String)\n    end\n  end\n\n  Generic = Class.new(self)\n\n  self.buildable_classes = [WithString, Generic]\n  # or, vice versa\n  def self.buildable_classes\n    [WithString, Generic]\n  end\nend\n\nAbstract.build(\"foo\") # =\u003e WithString.new(\"foo\")\nAbstract.build(:foo) # =\u003e Generic.new(\"foo\")\n```\n\nor see it at rubydoc.info\n\nWhy don't just use Uber::Builder?\n([Uber](https://github.com/apotonick/uber) is cool, you should try it)\nThere are two reasons: firstly, it is an unnecessary dependency.\nWe dont want npm hell, do we? Uber::Builder realy does not do much work,\nit's just a pattern. Secondly, this implementation looks more clear to me,\nbecause children are deciding whether they will handle arguments, not parents.\n\nSo to use it, you have to:\n\n1. Write some classes with duck type `.class_builder(*args)`\n\n2. Invoke `Verifly::ClassBuilder.new([\u003c%= array_of_classes %\u003e]).call(*args)`\n\n3. ????\n\n4. PROFIT\n\nIt's simple and clear, but not very sugary. So, otherwise, you may do\nfollowing:\n\n1. Write an abstract class\n\n2. Extend `Verifly::ClassBuilder::Mixin`\n\n3. Inherit from the abstract class in different implementations\n\n4. If some implementations have common ancestors\n(not including the abstract class), you can implement common ancestor's\n`.build_class` in terms of super (i.e.\n`def self.build_class(x); super if x.is_a?(String); end`)\n\n5. Change `.build_class` of other classes like `self if ...`.\nDon't change default implementation's `.build_class`\n\n6. Setup `.buildable_classes` on the abstract class, mentioning only direct\nchildren if you done step 4\n\n7. Optionally redefine `.build` in abstract class, if you want\nto separate `build_class` and constructor params\n\n8. Use `.build` instead of `new`\n\n## Applicator\n\nApplicator is designed to wrap applications of\n[applicable](https://en.wikipedia.org/wiki/Sepulka) objects\naround some binding in some context\n\nexample:\n\n```lang=ruby\nobject = OpenStruct.new(foo: :bar)\nApplicator.call(:foo, object, {}) # =\u003e :bar\nApplicator.call('foo', object, {}) # =\u003e :bar\nApplicator.call('context', object, {}) # =\u003e {}\nApplicator.call(-\u003e { foo }, object, {}) # =\u003e :bar\nApplicator.call(-\u003e(context) { context[foo] }, object, bar: :baz) # =\u003e :baz\nApplicator.call(true, object, {}) # =\u003e true\n\nfoo = :bar\nApplicator.call(:foo, binding, {}) # =\u003e :bar\nApplicator.call('object.foo', binding, {}) # =\u003e :bar\n```\n\nApplicator is good, but in most cases\n[ApplicatorWithOptions](#ApplicatorWithOptions) would be a better option.\n\n## ApplicatorWithOptions\n\nApplicatorWithOptions is an applicator with options.\nThe options are `if: ` and `unless: `. Same as in ActiveModel::Validations,\nthey are applied to the same binding. Main action is executed\nonly if `if: ` evaluates to truthy and `unless: ` evaluates to falsey.\n\nSee examples:\n\n```lang=ruby\nApplicatorWithOptions.new(:foo, if: -\u003e { true }).call(binding, {}) # =\u003e foo\n\nApplicatorWithOptions.new(:foo, if: -\u003e (context) { context[:bar] })\n  .call(binding, { bar: true }) # =\u003e foo\n\nApplicatorWithOptions.new(:foo, if: { bar: true }).call(binding, :bar) # =\u003e foo\n\nApplicatorWithOptions.new(:foo, unless: -\u003e { true })\n  .call(binding, {}) # =\u003e nil\nApplicatorWithOptions.new(:foo, unless: -\u003e (context) { context[:bar] })\n  .call(binding, { bar: true }) # =\u003e foo\nApplicatorWithOptions.new(:foo, unless: { bar: true })\n  .call(binding, :bar) # =\u003e nil\n```\n\n## Verifier\n\nThe last, but the most interesting component is Verifier.\nVerifiers use ApplciatorWithOptions to execute generic procedures.\nProcedures should call `message!` if they want to yield something.\nNote that you should implement `message!` by yourself (in terms of super)\n\n```lang=ruby\nclass MyVerifier \u003c Verifly::Verifier\n  Message = Struct.new(:text)\n  verify :foo, if: { foo: true }\n\n  private\n\n  def message!(text)\n    super { Message.new(text) }\n  end\n\n  def foo\n    message!('Something is wrong') if Fixnum != Bignum\n  end\nend\n```\n\nIn addition to Applicator's power, you also can nest your verifiers\nto split the logic\n\n```lang=ruby\nclass MyVerifier \u003c Verifly::Verifier\n  Message = Struct.new(:text)\n  verify_with ChildVerifier, if: -\u003e (context) { cotnext[:foo] }\n\n  private\n\n  def message!(text)\n    super { Message.new(text) }\n  end\nend\n\nclass ChildVerifier \u003c MyVerifier\n  verify %q(message!(\"it's alive!\"))\nend\n```\n\n## Yard documentation\n\nThis gem uses yard to generate documentation about its API.\nVisit http://www.rubydoc.info/github/umbrellio/verifly/master to see\nactual documentation for master.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fumbrellio%2Fverifly","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fumbrellio%2Fverifly","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fumbrellio%2Fverifly/lists"}