{"id":17767908,"url":"https://github.com/marceloboeira/prezzo","last_synced_at":"2025-03-15T14:30:27.941Z","repository":{"id":56888754,"uuid":"80214170","full_name":"marceloboeira/prezzo","owner":"marceloboeira","description":"💰Toolbox to create complex pricing models","archived":false,"fork":false,"pushed_at":"2017-07-17T09:42:02.000Z","size":85,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-04-27T01:02:22.055Z","etag":null,"topics":["calculator","complex-pricing-models","prezzo","price","pricing","ruby","toolbox"],"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/marceloboeira.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-27T14:29:27.000Z","updated_at":"2018-07-25T14:43:50.000Z","dependencies_parsed_at":"2022-08-20T16:00:29.517Z","dependency_job_id":null,"html_url":"https://github.com/marceloboeira/prezzo","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marceloboeira%2Fprezzo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marceloboeira%2Fprezzo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marceloboeira%2Fprezzo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marceloboeira%2Fprezzo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marceloboeira","download_url":"https://codeload.github.com/marceloboeira/prezzo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243742494,"owners_count":20340658,"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":["calculator","complex-pricing-models","prezzo","price","pricing","ruby","toolbox"],"created_at":"2024-10-26T20:52:01.080Z","updated_at":"2025-03-15T14:30:27.573Z","avatar_url":"https://github.com/marceloboeira.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Prezzo [![Build Status](https://travis-ci.org/marceloboeira/prezzo.svg?branch=master)](https://travis-ci.org/marceloboeira/prezzo) [![Code Climate](https://codeclimate.com/github/marceloboeira/prezzo.png)](https://codeclimate.com/github/marceloboeira/prezzo)\n\u003e Toolbox to create complex pricing models\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem \"prezzo\"\n```\n\nAnd then execute:\n\n```\n$ bundle\n```\n\nOr install it yourself as:\n\n```\n$ gem install prezzo\n```\n\n## Usage\n\n### Prezzo::Context\n\n\nThe `Prezzo::Context` is a source of data for your calculators. Basically, it receives a hash of params and it validates its content, in order to make the calculations safe.\n\ne.g.:\n\n```ruby\nmodule Uber\n  class Context\n    include Prezzo::Context\n    CATEGORIES = [\"UberX\", \"UberXL\", \"UberBlack\"].freeze\n\n    validations do\n      required(:category).filled(included_in?: CATEGORIES)\n      required(:distance).filled(:float?)\n      required(:total_cars).filled(:int?)\n      required(:available_cars).filled(:int?)\n    end\n  end\nend\n\ncontext = Uber::Context.new(category: \"UberBlack\", ...)\n\n# when valid\ncontext.valid?\n#=\u003e true\n\n# when invalid\ncontext.valid?\n#=\u003e false\n\ncontext.errors\n# { distance: [\"must be a float\"]}\n```\n\n### Prezzo::Calculator\n\nThe `Prezzo::Calculator` is a simple interface for injecting dependencies on your calculators and calculating the price. Basically, it makes it possible to receive the context, an Hash of parameters containing the necessary information to calculate your price or a Prezzo::Context.\n\ne.g.:\n\n```ruby\nrequire \"prezzo\"\n\nmodule Uber\n  class PricePerDistanceCalculator\n    include Prezzo::Calculator\n\n    def calculate\n      price_per_kilometer * distance\n    end\n\n    def price_per_kilometer\n      1.30\n    end\n\n    def distance\n      context.fetch(:distance)\n    end\n  end\nend\n\ncontext = Uber::Context.new(distance: 10.0)\nUber::PricePerDistanceCalculator.new(context).calculate\n#=\u003e 20.0\n```\n\n**Context Validation**\n\nIf you initialize the context with a hash, it will skip the validation, however, any object that responds to `.valid?` will attempt a validation, and it will fail if valid? returns false.\n\n### Prezzo::Composable\n\nThe `Prezzo::Composable` module is an abstraction that provides a nice way of injecting other calculators define how the price will be composed with all of those calculators.\n\ne.g.:\n\n```ruby\nrequire \"prezzo\"\n\nmodule Uber\n  class RidePriceCalculator\n    include Prezzo::Calculator\n    include Prezzo::Composable\n\n    composed_by base_fare: BaseFareCalculator,\n                price_per_distance: PricePerDistanceCalculator,\n\n    def calculate\n      base_fare + price_per_distance\n    end\n  end\nend\n\ncontext = Uber::Context.new(distance: 10.0)\nUber::RidePriceCalculator.new(context).calculate\n#=\u003e 47.3\n```\n\n### Prezzo::Explainable\n\nThe `Prezzo::Explainable` module is an abstraction that provides a nice way of representing how the price was composed.\n\ne.g.:\n\n```ruby\nrequire \"prezzo\"\n\nmodule Uber\n  class RidePriceCalculator\n    include Prezzo::Calculator\n    include Prezzo::Composable\n    include Prezzo::Explainable\n\n    composed_by base_fare: BaseFareCalculator,\n                price_per_distance: PricePerDistanceCalculator,\n    explain_with :base_fare, :price_per_distance\n\n    def calculate\n      base_fare + price_per_distance\n    end\n  end\nend\n\ncontext = Uber::Context.new(distance: 10.0)\nUber::RidePriceCalculator.new(context).explain\n#=\u003e { total: 25.6, components: { base_fare: 4.3, price_per_distance: 21.3 } }\n```\n\n#### Multiline `explain_with`\n\n`explain_with` can be splitted into several lines.\n\n```ruby\nclass RidePriceCalculator\n  include Prezzo::Explainable\n\n  explain_with :base_fare\n  explain_with :price_per_distance\nend\n```\n\n#### ` explain_with` with the `recursive: false` option\n\n```ruby\nclass FooCalculator\n  include Prezzo::Calculator\n  include Prezzo::Explainable\n\n  explain_with :bar, :baz\n\n  def calculate\n    bar + baz\n  end\n\n  def bar\n    10\n  end\n\n  def baz\n    20\n  end\nend\n\nclass QuxCalculator\n  include Prezzo::Calculator\n  include Prezzo::Composable\n  include Prezzo::Explainable\n\n  composed_by foo: FooCalculator\n\n  explain_with :foo, recursive: false\n\n  def calculate\n    foo + 5\n  end\nend\n```\n\n`QuxCalculator#explain` now produces\n\n```ruby\n{\n  total: 35,\n  components: {\n    foo: 30\n  }\n}\n```\n\nbut not\n\n```ruby\n{\n  total: 35,\n  components: {\n    foo: {\n      total: 30,\n      components: {\n        bar: 10,\n        baz: 20\n      }\n    }\n  }\n}\n```\n\nCheck the full [Uber pricing](/spec/integration/uber_pricing_spec.rb) for more complete example with many calculators and factors.\n\n## Development\n\nAfter checking out the repo, run `make` to install dependencies. Then, run `make spec` to run the tests. You can also run `make console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `make install`. To release a new version, update the version number in `version.rb`, and then run `make 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).\n\n## Contributing\n\nPlease consider reading out [Contributing Guide](CONTRIBUTING.md).\n\nThis project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarceloboeira%2Fprezzo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarceloboeira%2Fprezzo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarceloboeira%2Fprezzo/lists"}