[
  {
    "path": ".coveralls.yml",
    "content": "repo_token: M3JnILwxCIYb4OjWvyxBJkib9xsAGdnek\n"
  },
  {
    "path": ".gitignore",
    "content": "Gemfile.lock\n.rspec-local\n*.gem\nlib/1.8\nlib/1.9\nlib/2.0\n.rvmrc\n.ruby-version\n.ruby-gemset\n.bundle/*\n.yardoc/*\nyardoc/*\ntmp/*\nman/*\n*.tmproj\nrdoc/*\n*.orig\n*.BACKUP.*\n*.BASE.*\n*.LOCAL.*\n*.REMOTE.*\ngit_pull.txt\ncoverage\ncritic\n.DS_Store\nTAGS\ntmtags\n*.sw?\n.idea\n.rbx/*\nlib/*.bundle\nlib/*.so\nlib/*.jar\next/*.bundle\next/*.so\next/*.jar\npkg\n*.gem\n"
  },
  {
    "path": ".rspec",
    "content": "--require spec_helper\n--format progress\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: ruby\n\nrvm:\n  - 2.2.3\n  - 2.2.2\n  - 2.2.1\n  - 2.1.5\n  - 2.1.4\n  - 2.0.0\n  - ruby-head\n  - jruby-1.7.19\n  - jruby-9.0.1.0\n  - jruby-9.0.3.0\n  - jruby-9.0.4.0\n  - jruby-head\n  - rbx-2\n\njdk:\n  - oraclejdk8\n\nsudo: false\n\nbranches:\n  only:\n    - master\n\nmatrix:\n  allow_failures:\n    - rvm: ruby-head\n    - rvm: jruby-head\n    - rvm: jruby-9.0.1.0\n    - rvm: rbx-2\n\nscript: \"CODECLIMATE_REPO_TOKEN=65d4787423f734f5cf6d2b3f9be88e481802e50af0879e8ed66971f972d70894 bundle exec rake\"\n"
  },
  {
    "path": ".yardopts",
    "content": "--protected\n--no-private\n--embed-mixins\n--output-dir ./yardoc\n--markup markdown\n--title=Functional Ruby\n--template default\n\n./lib/**/*.rb\n-\nREADME.md\nCHANGELOG.md\nLICENSE\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## Current Release v1.3.0 (October 4, 2015)\n\n* Pattern match now check arity of pattern and block\n* `PatternMatching::ALL` pattern now should be presented as variable length args (*args)\n* `NoMethodError` and `ArgumentError` raised from method block won't be catched anymore by lib\n\n### Release v1.2.0 (July 10, 2015)\n\n* `Record` classes can be declared with a type/protocol specification for type safety.\n* Improved documentation\n* Improved tests\n* Better synchronization (thread safety) on all platforms\n* Continuous integration run on both Linux (Travis CI) and Windows (AppVeyor)\n\n### Release v1.1.0 (August 12, 2014)\n\n* A simple implementation of [tuple](http://en.wikipedia.org/wiki/Tuple), an\n  immutable, fixed-length list/array/vector-like data structure.\n* `FinalStruct`, a variation on Ruby's `OpenStruct` in which all fields are \"final\" (meaning\n  that new fields can be arbitrarily added but once set each field becomes immutable).\n* `FinalVar`, a thread safe object that holds a single value and is \"final\" (meaning\n  that the value can be set at most once after which it becomes immutable).\n\n### Release v1.0.0 (July 30, 2014)\n\n* Protocol specifications inspired by Clojure [protocol](http://clojure.org/protocols),\n  Erlang [behavior](http://www.erlang.org/doc/design_principles/des_princ.html#id60128),\n  and Objective-C [protocol](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithProtocols/WorkingwithProtocols.html)\n* Function overloading with Erlang-style [function](http://erlang.org/doc/reference_manual/functions.html)\n  [pattern matching](http://erlang.org/doc/reference_manual/patterns.html)\n* Simple, immutable data structures, such as *record* and *union*, inspired by\n  [Clojure](http://clojure.org/datatypes), [Erlang](http://www.erlang.org/doc/reference_manual/records.html),\n  and [others](http://en.wikipedia.org/wiki/Union_type)\n* `Either` and `Option` classes based on [Functional Java](http://functionaljava.org/) and [Haskell](https://hackage.haskell.org/package/base-4.2.0.1/docs/Data-Either.html)\n* [Memoization](http://en.wikipedia.org/wiki/Memoization) of class methods based on Clojure [memoize](http://clojuredocs.org/clojure_core/clojure.core/memoize)\n* Lazy execution with a `Delay` class based on Clojure [delay](http://clojuredocs.org/clojure_core/clojure.core/delay)\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Code of Conduct\n\nAs contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.\n\nWe are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery\n* Personal attacks\n* Trolling or insulting/derogatory comments\n* Public or private harassment\n* Publishing other's private information, such as physical or electronic addresses, without explicit permission\n* Other unethical or unprofessional conduct.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.\n\nThis code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.\n\nThis Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)\n"
  },
  {
    "path": "Gemfile",
    "content": "source 'https://rubygems.org'\n\ngemspec\n\ngroup :development do\n  gem 'rake', '~> 12.3.0'\nend\n\ngroup :testing do\n  gem 'rspec', '~> 3.7.0'\n  gem 'simplecov', '~> 0.14.1', platforms: :mri, require: false\n  gem 'coveralls', '~> 0.8.21', require: false\nend\n\ngroup :documentation do\n  gem 'countloc', '~> 0.4.0', platforms: :mri, require: false\n  gem 'yard', '~> 0.9.12', require: false\n  gem 'redcarpet', '~> 3.4.0', platforms: :mri # understands github markdown\nend\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) Jerry D'Antonio -- released under the MIT license.\n\nhttp://www.opensource.org/licenses/mit-license.php  \n\nPermission is hereby granted, free of charge, to any person obtaining a copy  \nof this software and associated documentation files (the \"Software\"), to deal  \nin the Software without restriction, including without limitation the rights  \nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell  \ncopies of the Software, and to permit persons to whom the Software is  \nfurnished to do so, subject to the following conditions:  \n \nThe above copyright notice and this permission notice shall be included in  \nall copies or substantial portions of the Software.  \n \nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  \nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  \nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  \nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  \nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  \nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN  \nTHE SOFTWARE. \n"
  },
  {
    "path": "README.md",
    "content": "# Functional Ruby\n[![Gem Version](https://badge.fury.io/rb/functional-ruby.svg)](http://badge.fury.io/rb/functional-ruby)\n[![Travis CI Build Status](https://secure.travis-ci.org/jdantonio/functional-ruby.png)](https://travis-ci.org/jdantonio/functional-ruby?branch=master)\n[![AppVeyor Build status](https://ci.appveyor.com/api/projects/status/8xfy4a8lmc26112e/branch/master?svg=true)](https://ci.appveyor.com/project/jdantonio/functional-ruby/branch/master)\n[![Coverage Status](https://coveralls.io/repos/jdantonio/functional-ruby/badge.png)](https://coveralls.io/r/jdantonio/functional-ruby)\n[![Code Climate](https://codeclimate.com/github/jdantonio/functional-ruby.png)](https://codeclimate.com/github/jdantonio/functional-ruby)\n[![Inline docs](http://inch-ci.org/github/jdantonio/functional-ruby.png)](http://inch-ci.org/github/jdantonio/functional-ruby)\n[![Dependency Status](https://gemnasium.com/jdantonio/functional-ruby.png)](https://gemnasium.com/jdantonio/functional-ruby)\n[![License](http://img.shields.io/license/MIT.png?color=green)](http://opensource.org/licenses/MIT)\n\n**A gem for adding functional programming tools to Ruby. Inspired by [Erlang](http://www.erlang.org/),\n[Clojure](http://clojure.org/), and [Functional Java](http://functionaljava.org/).**\n\n## Introduction\n\nTwo things I love are [Ruby](http://www.ruby-lang.org/en/) and\n[functional](https://en.wikipedia.org/wiki/Functional_programming)\n[programming](http://c2.com/cgi/wiki?FunctionalProgramming).\nIf you combine Ruby's ability to create functions sans-classes with the power\nof blocks, `proc`, and `lambda`, Ruby code can follow just about every modern functional\nprogramming design paradigm. Add to this Ruby's vast metaprogramming capabilities\nand Ruby is easily one of the most powerful languages in common use today.\n\n### Goals\n\nOur goal is to implement various functional programming patterns in Ruby. Specifically:\n\n* Be an 'unopinionated' toolbox that provides useful utilities without debating which is better or why\n* Remain free of external gem dependencies\n* Stay true to the spirit of the languages providing inspiration\n* But implement in a way that makes sense for Ruby\n* Keep the semantics as idiomatic Ruby as possible\n* Support features that make sense in Ruby\n* Exclude features that don't make sense in Ruby\n* Keep everything small\n* Be as fast as reasonably possible\n\n## Features\n\nThe primary site for documentation is the automatically generated [API documentation](http://jdantonio.github.io/functional-ruby/).\n\n* Protocol specifications inspired by Clojure [protocol](http://clojure.org/protocols),\n  Erlang [behavior](http://www.erlang.org/doc/design_principles/des_princ.html#id60128),\n  and Objective-C [protocol](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithProtocols/WorkingwithProtocols.html).\n* Function overloading with Erlang-style [function](http://erlang.org/doc/reference_manual/functions.html)\n  [pattern matching](http://erlang.org/doc/reference_manual/patterns.html).\n* Simple, thread safe, immutable data structures, such as `Record`, `Union`, and `Tuple`, inspired by\n  [Clojure](http://clojure.org/datatypes), [Erlang](http://www.erlang.org/doc/reference_manual/records.html),\n  and other functional languages.\n* Thread safe, immutable `Either` and `Option` classes based on [Functional Java](http://functionaljava.org/) and [Haskell](https://hackage.haskell.org/package/base-4.2.0.1/docs/Data-Either.html).\n* [Memoization](http://en.wikipedia.org/wiki/Memoization) of class methods based on Clojure [memoize](http://clojuredocs.org/clojure_core/clojure.core/memoize).\n* Lazy execution with a `Delay` class based on Clojure [delay](http://clojuredocs.org/clojure_core/clojure.core/delay).\n* `ValueStruct`, a simple, thread safe, immutable variation of Ruby's [OpenStruct](http://ruby-doc.org/stdlib-2.0/libdoc/ostruct/rdoc/OpenStruct.html) class.\n* Thread safe data structures, such as `FinalStruct` and `FinalVar`, which can be written to at most once\n  before becoming immutable. Based on [Java's `final` keyword](http://en.wikipedia.org/wiki/Final_(Java)).\n\n### Supported Ruby Versions\n\nMRI 2.0 and higher, JRuby (1.9 mode), and Rubinius 2.x. This library is pure Ruby and has no gem dependencies.\nIt should be fully compatible with any interpreter that is compliant with Ruby 2.0 or newer.\n\n### Install\n\n```shell\ngem install functional-ruby\n```\n\nor add the following line to Gemfile:\n\n```ruby\ngem 'functional-ruby'\n```\n\nand run `bundle install` from your shell.\n\nOnce you've installed the gem you must `require` it in your project:\n\n```ruby\nrequire 'functional'\n```\n\n## Examples\n\nSpecifying a [protocol](http://rubydoc.info/github/jdantonio/functional-ruby/master/Functional/Protocol):\n\n```ruby\nFunctional::SpecifyProtocol(:Name) do\n  attr_accessor :first\n  attr_accessor :middle\n  attr_accessor :last\n  attr_accessor :suffix\nend\n```\n\nDefining immutable [data structures](http://rubydoc.info/github/jdantonio/functional-ruby/master/Functional/AbstractStruct) including\n[Either](http://rubydoc.info/github/jdantonio/functional-ruby/master/Functional/Either),\n[Option](http://rubydoc.info/github/jdantonio/functional-ruby/master/Functional/Option),\n[Union](http://rubydoc.info/github/jdantonio/functional-ruby/master/Functional/Union) and\n[Record](http://rubydoc.info/github/jdantonio/functional-ruby/master/Functional/Record)\n\n```ruby\nName = Functional::Record.new(:first, :middle, :last, :suffix) do\n  mandatory :first, :last\n  default :first, 'J.'\n  default :last, 'Doe'\nend\n\nanon = Name.new #=> #<record Name :first=>\"J.\", :middle=>nil, :last=>\"Doe\", :suffix=>nil>\nmatz = Name.new(first: 'Yukihiro', last: 'Matsumoto') #=> #<record Name :first=>\"Yukihiro\", :middle=>nil, :last=>\"Matsumoto\", :suffix=>nil>\n```\n\n[Pattern matching](http://rubydoc.info/github/jdantonio/functional-ruby/master/Functional/PatternMatching)\nusing [protocols](http://rubydoc.info/github/jdantonio/functional-ruby/master/Functional/Protocol),\n[type](http://rubydoc.info/github/jdantonio/functional-ruby/master/Functional/TypeCheck) checking,\nand other options:\n\n```ruby\nclass Foo\n  include Functional::PatternMatching\n  include Functional::Protocol\n  include Functional::TypeCheck\n\n  def greet\n    return 'Hello, World!'\n  end\n\n  defn(:greet, _) do |name|\n    \"Hello, #{name}!\"\n  end\n\n  defn(:greet, _) { |name|\n    \"Pleased to meet you, #{name.full_name}!\"\n  }.when {|name| Type?(name, CustomerModel, ClientModel) }\n\n  defn(:greet, _) { |name|\n    \"Hello, #{name.first} #{name.last}!\"\n  }.when {|name| Satisfy?(name, :Name) }\n\n  defn(:greet, :doctor, _) { |name|\n    \"Hello, Dr. #{name}!\"\n  }\n\n  defn(:greet, nil, _) { |name|\n    \"Goodbye, #{name}!\"\n  }\n\n  defn(:greet, _, _) { |_, name|\n    \"Hello, #{name}!\"\n  }\nend\n```\n\nPerformance improvement of idempotent functions through [memoization](http://rubydoc.info/github/jdantonio/functional-ruby/master/Functional/Memo):\n\n```ruby\nclass Factors\n  include Functional::Memo\n\n  def self.sum_of(number)\n    of(number).reduce(:+)\n  end\n\n  def self.of(number)\n    (1..number).select {|i| factor?(number, i)}\n  end\n\n  def self.factor?(number, potential)\n    number % potential == 0\n  end\n\n  memoize(:sum_of)\n  memoize(:of)\nend\n```\n\n## Contributing\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create new Pull Request\n\n## License and Copyright\n\n*Functional Ruby* is free software released under the [MIT License](http://www.opensource.org/licenses/MIT).\n"
  },
  {
    "path": "Rakefile",
    "content": "$:.push File.join(File.dirname(__FILE__), 'lib')\n\nGEMSPEC = Gem::Specification.load('functional-ruby.gemspec')\n\nrequire 'bundler/gem_tasks'\nrequire 'rspec'\nrequire 'rspec/core/rake_task'\n\nrequire 'functional'\n\nBundler::GemHelper.install_tasks\n\nDir.glob('tasks/**/*.rake').each do|rakefile|\n  load rakefile\nend\n\nRSpec::Core::RakeTask.new(:spec) do |t|\n  t.rspec_opts = '--color --backtrace --format documentation'\nend\n\nRSpec::Core::RakeTask.new(:travis_spec) do |t|\n  t.rspec_opts = '--tag ~@not_on_travis'\nend\n\ntask :default => [:travis_spec]\n"
  },
  {
    "path": "appveyor.yml",
    "content": "install:\n  - SET PATH=C:\\Ruby%ruby_version%\\bin;%PATH%\n  - SET PATH=C:\\MinGW\\bin;%PATH%\n  - SET RAKEOPT=-rdevkit\n  - ruby --version\n  - gem --version\n  - bundle install\n\nbuild: off\n\ntest_script:\n  - bundle exec rake\n\nenvironment:\n  matrix:\n    - ruby_version: \"200\"\n    - ruby_version: \"200-x64\"\n    - ruby_version: \"21\"\n    - ruby_version: \"21-x64\"\n    - ruby_version: \"22\"\n    - ruby_version: \"22-x64\"\n\n#matrix:\n  #allow_failures:\n    #- ruby_version: \"193\"\n"
  },
  {
    "path": "doc/memo.md",
    "content": "# memoize\n\n###    Rationale\n\n   Many computational operations take a significant amount of time and/or use\n   an inordinate amount of resources. If subsequent calls to that function with\n   the same parameters are guaranteed to return the same result, caching the\n   result can lead to significant performance improvements. The process of\n   caching such calls is called\n   [memoization](http://en.wikipedia.org/wiki/Memoization).\n\n###    Declaration\n\n   Using memoization requires two simple steps: including the\n   `Functional::Memo` module within a class or module and calling the `memoize`\n   function to enable memoization on one or more methods.\n\n   ```ruby\n   Module EvenNumbers\n     include Functional::Memoize\n\n     self.first(n)\n       (2..n).select{|i| i % 2 == 0 }\n     end\n\n     memoize :first\n   end\n   ```\n\n   When a function is memoized an internal cache is created that maps arguments\n   to return values. When the function is called the arguments are checked\n   against the cache. If the args are found the method is not called and the\n   cached result is returned instead.\n\n###    Ramifications\n\n   Memoizing long-running methods can lead to significant performance\n   advantages. But there is a trade-off. Memoization may greatly increase the\n   memory footprint of the application. The memo cache itself takes memory. The\n   more arg/result pairs stored in the cache, the more memory is consumed.\n\n#####    Cache Size Options\n\n   To help control the size of the cache, a limit can be placed on the number\n   of items retained in the cache. The `:at_most` option, when given, indicates\n   the maximum size of the cache. Once the maximum cache size is reached, calls\n   to to the method with uncached args will still result in the method being\n   called, but the results will not be cached.\n\n   ```ruby\n   Module EvenNumbers\n     include Functional::Memoize\n\n     self.first(n)\n       (2..n).select{|i| i % 2 == 0 }\n     end\n\n     memoize :first, at_most: 1000\n   end\n   ```\n\n   There is no way to predict in advance what the proper cache size is, or if\n   it should be restricted at all. Only performance testing under realistic\n   conditions or profiling of a running system can provide guidance.\n\n###    Restrictions\n\n   Not all methods are good candidates for memoization.Only methods that are\n   [idempotent](http://en.wikipedia.org/wiki/Idempotence), [referentially\n   transparent](http://en.wikipedia.org/wiki/Referential_transparency_(computer_science)),\n   and free of [side effects](http://en.wikipedia.org/wiki/Side_effect_(computer_science))\n   can be effectively memoized. If a method creates side effects, such as\n   writing to a log, only the first call to the method will create those side\n   effects. Subsequent calls will return the cached value without calling the\n   method.\n\n   Similarly, methods which change internal state will only update the state on\n   the initial call. Later calls will not result in state changes, they will\n   only return the original result. Subsequently, instance methods cannot be\n   memoized. Objects are, by definition, stateful. Method calls exist for the\n   purpose of changing or using the internal state of the object. Such methods\n   cannot be effectively memoized; it would require the internal state of the\n   object to be cached and checked as well.\n\n   Block parameters pose a similar problem. Block parameters are inherently\n   stateful (they are closures which capture the enclosing context). And there\n   is no way to check the state of the block along with the args to determine\n   if the cached value should be used. Subsequently, and method call which\n   includes a block will result in the cache being completely skipped. The base\n   method will be called and the result will not be cached. This behavior will\n   occur even when the given method was not programmed to accept a block\n   parameter. Ruby will capture any block passed to any method and make it\n   available to the method even when not documented as a formal parameter or\n   used in the method. This has the interesting side effect of allowing the\n   memo cache to be skipped on any method call, simply be passing a block\n   parameter.\n\n   ```ruby\n   EvenNumbers.first(100)         causes the result to be cached\n   EvenNumbers.first(100)         retrieves the previous result from the cache\n   EvenNumbers.first(100){ nil }  skips the memo cache and calls the method again\n   ```\n\n###   Complete Example\n\n   The following example is borrowed from the book [Functional Thinking](http://shop.oreilly.com/product/0636920029687.do)\n   by Neal Ford. In his book he shows an example of memoization in Groovy by\n   summing factors of a given number. This is a great example because it\n   exhibits all the criteria that make a method a good memoization candidate:\n\n   * Idempotence\n   * Referential transparency\n   * Stateless\n   * Free of side effect\n   * Computationally expensive (for large numbers)\n\n   The following code implements Ford's algorithms in Ruby, then memoizes two\n   key methods. The Ruby code:\n\n   ```ruby\n   require 'functional'\n\n   class Factors\n     include Functional::Memo\n\n     def self.sum_of(number)\n       of(number).reduce(:+)\n     end\n\n     def self.of(number)\n       (1..number).select {|i| factor?(number, i)}\n     end\n\n     def self.factor?(number, potential)\n       number % potential == 0\n     end\n\n     def self.perfect?(number)\n       sum_of(number) == 2 * number\n     end\n\n     def self.abundant?(number)\n       sum_of(number) > 2 * number\n     end\n\n     def self.deficient?(number)\n       sum_of(number) < 2 * number\n     end\n\n     memoize(:sum_of)\n     memoize(:of)\n   end\n   ```\n\n   This code was tested in IRB using MRI 2.1.2 on a MacBook Pro. The `sum_of`\n   method was called three times against the number 10,000,000 and the\n   benchmark results of each run were captured. The test code:\n\n   ```ruby\n   require 'benchmark'\n\n   3.times do\n     stats = Benchmark.measure do\n       Factors.sum_of(10_000_000)\n     end\n     puts stats\n   end\n   ```\n\n   The results of the benchmarking are very revealing. The first run took over\n   a second to calculate the results. The two subsequent runs, which retrieved\n   the previous result from the memo cache, were nearly instantaneous:\n\n   ```\n   1.080000   0.000000   1.080000 (  1.077524)\n   0.000000   0.000000   0.000000 (  0.000033)\n   0.000000   0.000000   0.000000 (  0.000008)\n   ```\n\n   The same code run on the same computer using JRuby 1.7.12 exhibited similar\n   results:\n\n   ```\n   1.800000   0.030000   1.830000 (  1.494000)\n   0.000000   0.000000   0.000000 (  0.000000)\n   0.000000   0.000000   0.000000 (  0.000000)\n   ```\n\n###    Inspiration\n\n   * [Memoization](http://en.wikipedia.org/wiki/Memoization) at Wikipedia\n   * Clojure [memoize](http://clojuredocs.org/clojure_core/clojure.core/memoize) function\n"
  },
  {
    "path": "doc/memoize.rb",
    "content": "#!/usr/bin/env ruby\n$LOAD_PATH << File.expand_path('../../lib', __FILE__)\n\nrequire 'functional'\n\nclass Factors\n  include Functional::Memo\n\n  def self.sum_of(number)\n    of(number).reduce(:+)\n  end\n\n  def self.of(number)\n    (1..number).select {|i| factor?(number, i)}\n  end\n\n  def self.factor?(number, potential)\n    number % potential == 0\n  end\n\n  def self.perfect?(number)\n    sum_of(number) == 2 * number\n  end\n\n  def self.abundant?(number)\n    sum_of(number) > 2 * number\n  end\n\n  def self.deficient?(number)\n    sum_of(number) < 2 * number\n  end\n\n  memoize(:sum_of)\n  memoize(:of)\nend\n\nrequire 'benchmark'\nrequire 'pp'\n\ndef memory_usage\n  `ps ax -o pid,rss | grep -E \"^[[:space:]]*#{$$}\"`.strip.split.map(&:to_i)\nend\n\ndef print_memory_usage\n  pid, size = memory_usage\n  puts \"Memory used by process #{pid} at #{Time.now} is #{size}\"\nend\n\ndef run_benchmark(n = 10000)\n\n  puts \"Benchmarks for #{n} numbers...\"\n  puts\n\n  puts 'With no memoization...'\n  stats = Benchmark.measure do\n    Factors.sum_of(n)\n  end\n  puts stats\n\n  2.times do\n    puts\n    puts 'With memoization...'\n    stats = Benchmark.measure do\n      Factors.sum_of(n)\n    end\n    puts stats\n  end\nend\n\nif $0 == __FILE__\n  run_benchmark(10_000_000)\nend\n\n__END__\n\n$ ./doc/memoize.rb\nBenchmarks for 10000000 numbers...\n\nWith no memoization...\n  1.660000   0.000000   1.660000 (  1.657253)\n\nWith memoization...\n  0.000000   0.000000   0.000000 (  0.000019)\n\nWith memoization...\n  0.000000   0.000000   0.000000 (  0.000008)\n"
  },
  {
    "path": "doc/pattern_matching.md",
    "content": "###    Features\n\n   * Pattern matching for instance methods.\n   * Pattern matching for object constructors.\n   * Parameter count matching\n   * Matching against primitive values\n   * Matching by class/datatype\n   * Matching against specific key/vaue pairs in hashes\n   * Matching against the presence of keys within hashes\n   * Implicit hash for last parameter\n   * Variable-length parameter lists\n   * Guard clauses\n   * Recursive calls to other pattern matches\n   * Recursive calls to superclass pattern matches\n   * Recursive calls to superclass methods\n   * Dispatching to superclass methods when no match is found\n   * Reasonable error messages when no match is found\n\n###    Usage\n\n   First, familiarize yourself with Erlang [pattern matching](http://learnyousomeerlang.com/syntax-in-functionspattern-matching).\n   This gem may not make much sense if you don't understand how Erlang dispatches functions.\n\n   In the Ruby class file where you want to use pattern matching, require the *functional-ruby* gem:\n\n   ```ruby\n   require 'functional'\n   ```\n\n   Then include `Functional::PatternMatching` in your class:\n\n   ```ruby\n   require 'functional'\n\n   class Foo\n     include Functional::PatternMatching\n\n     ...\n\n   end\n   ```\n\n   You can then define functions with `defn` instead of the normal *def* statement.\n   The syntax for `defn` is:\n\n   ```ruby\n   defn(:symbol_name_of_function, zero, or, more, parameters) { |block, arguments|\n      code to execute\n   }\n   ```\n   You can then call your new function just like any other:\n\n   ```ruby\n   require 'functional/pattern_matching'\n\n   class Foo\n     include Functional::PatternMatching\n\n     defn(:hello) {\n       puts \"Hello, World!\"\n     }\n   end\n\n   foo = Foo.new\n   foo.hello => \"Hello, World!\"\n   ```\n\n   Patterns to match against are included in the parameter list:\n\n   ```ruby\n   defn(:greet, :male) {\n     puts \"Hello, sir!\"\n   }\n\n   defn(:greet, :female) {\n     puts \"Hello, ma'am!\"\n   }\n\n   ...\n\n   foo.greet(:male)   => \"Hello, sir!\"\n   foo.greet(:female) => \"Hello, ma'am!\"\n   ```\n\n   If a particular method call can not be matched a *NoMethodError* is thrown with\n   a reasonably helpful error message:\n\n   ```ruby\n   foo.greet(:unknown) => NoMethodError: no method `greet` matching [:unknown] found for class Foo\n   foo.greet           => NoMethodError: no method `greet` matching [] found for class Foo\n   ```\n\n   Parameters that are expected to exist but that can take any value are considered\n   *unbound* parameters. Unbound parameters are specified by the `_` underscore\n   character or `UNBOUND`:\n\n   ```ruby\n   defn(:greet, _) do |name|\n     \"Hello, {name}!\"\n   end\n\n   defn(:greet, UNBOUND, UNBOUND) do |first, last|\n     \"Hello, {first} {last}!\"\n   end\n\n   ...\n\n   foo.greet('Jerry') => \"Hello, Jerry!\"\n   ```\n\n   All unbound parameters will be passed to the block in the order they are specified in the definition:\n\n   ```ruby\n   defn(:greet, _, _) do |first, last|\n     \"Hello, {first} {last}!\"\n   end\n\n   ...\n\n   foo.greet('Jerry', \"D'Antonio\") => \"Hello, Jerry D'Antonio!\"\n   ```\n\n   If for some reason you don't care about one or more unbound parameters within\n   the block you can use the `_` underscore character in the block parameters list\n   as well:\n\n   ```ruby\n   defn(:greet, _, _, _) do |first, _, last|\n     \"Hello, {first} {last}!\"\n   end\n\n   ...\n\n   foo.greet('Jerry', \"I'm not going to tell you my middle name!\", \"D'Antonio\") => \"Hello, Jerry D'Antonio!\"\n   ```\n\n   Hash parameters can match against specific keys and either bound or unbound parameters. This allows for\n   function dispatch by hash parameters without having to dig through the hash:\n\n   ```ruby\n   defn(:hashable, {foo: :bar}) { |opts|\n     :foo_bar\n   }\n   defn(:hashable, {foo: _}) { |f|\n     f\n   }\n\n   ...\n\n   foo.hashable({foo: :bar})      => :foo_bar\n   foo.hashable({foo: :baz})      => :baz\n   ```\n\n   The Ruby idiom of the final parameter being a hash is also supported:\n\n   ```ruby\n   defn(:options, _) { |opts|\n     opts\n   }\n\n   ...\n\n   foo.options(bar: :baz, one: 1, many: 2)\n   ```\n\n   As is the Ruby idiom of variable-length argument lists. The constant `ALL` as the last parameter\n   will match one or more arguments and pass them to the block as an array:\n\n   ```ruby\n   defn(:baz, Integer, ALL) { |int, args|\n     [int, args]\n   }\n   defn(:baz, ALL) { |args|\n     args\n   }\n   ```\n\n   Superclass polymorphism is supported as well. If an object cannot match a method\n   signature it will defer to the parent class:\n\n   ```ruby\n   class Bar\n     def greet\n       return 'Hello, World!'\n     end\n   end\n\n   class Foo < Bar\n     include Functional::PatternMatching\n\n     defn(:greet, _) do |name|\n       \"Hello, {name}!\"\n     end\n   end\n\n   ...\n\n   foo.greet('Jerry') => \"Hello, Jerry!\"\n   foo.greet          => \"Hello, World!\"\n   ```\n\n   Guard clauses in Erlang are defined with `when` clauses between the parameter list and the function body.\n   In Ruby, guard clauses are defined by chaining a call to `when` onto the the `defn` call and passing\n   a block. If the guard clause evaluates to true then the function will match. If the guard evaluates\n   to false the function will not match and pattern matching will continue:\n\n   Erlang:\n\n   ```erlang\n   old_enough(X) when X >= 16 -> true;\n   old_enough(_) -> false.\n   ```\n\n   Ruby:\n\n   ```ruby\n   defn(:old_enough, _){ |_| true }.when{|x| x >= 16 }\n   defn(:old_enough, _){ |_| false }\n   ```\n\n#####    Order Matters\n\n   As with Erlang, the order of pattern matches is significant. Patterns will be matched\n   *in the order declared* and the first match will be used. If a particular function call\n   can be matched by more than one pattern, the *first matched pattern* will be used. It\n   is the programmer's responsibility to ensure patterns are declared in the correct order.\n\n#####    Blocks and Procs and Lambdas, oh my!\n\n   When using this gem it is critical to remember that `defn` takes a block and\n   that blocks in Ruby have special rules. There are [plenty](https://www.google.com/search?q=ruby+block+proc+lambda)\n   of good tutorials on the web explaining [blocks](http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/)\n   and [Procs](https://coderwall.com/p/_-_mha) and [lambdas](http://railsguru.org/2010/03/learn-ruby-procs-blocks-lambda/)\n   in Ruby. Please read them. Please don't submit a bug report if you use a\n   `return` statement within your `defn` and your code blows up with a\n   [LocalJumpError](http://ruby-doc.org/core-2.0/LocalJumpError.html).\n\n#####    Examples\n\n   For more examples see the integration tests in *spec/integration_spec.rb*.\n\n    Simple Functions\n\n   This example is based on [Syntax in defnctions: Pattern Matching](http://learnyousomeerlang.com/syntax-in-defnctions) in [Learn You Some Erlang for Great Good!](http://learnyousomeerlang.com/).\n\n   Erlang:\n\n   ```erlang\n   greet(male, Name) ->\n     io:format(\"Hello, Mr. ~s!\", [Name]);\n   greet(female, Name) ->\n     io:format(\"Hello, Mrs. ~s!\", [Name]);\n   greet(_, Name) ->\n     io:format(\"Hello, ~s!\", [Name]).\n   ```\n\n   Ruby:\n\n   ```ruby\n   require 'functional/pattern_matching'\n\n   class Foo\n     include Functional::PatternMatching\n\n     defn(:greet, _) do |name|\n       \"Hello, {name}!\"\n     end\n\n     defn(:greet, :male, _) { |name|\n       \"Hello, Mr. {name}!\"\n     }\n     defn(:greet, :female, _) { |name|\n       \"Hello, Ms. {name}!\"\n     }\n     defn(:greet, _, _) { |_, name|\n       \"Hello, {name}!\"\n     }\n   end\n   ```\n\n#####    Simple Functions with Overloading\n\n   This example is based on [Syntax in defnctions: Pattern Matching](http://learnyousomeerlang.com/syntax-in-defnctions) in [Learn You Some Erlang for Great Good!](http://learnyousomeerlang.com/).\n\n   Erlang:\n\n   ```erlang\n   greet(Name) ->\n     io:format(\"Hello, ~s!\", [Name]).\n\n   greet(male, Name) ->\n     io:format(\"Hello, Mr. ~s!\", [Name]);\n   greet(female, Name) ->\n     io:format(\"Hello, Mrs. ~s!\", [Name]);\n   greet(_, Name) ->\n     io:format(\"Hello, ~s!\", [Name]).\n   ```\n\n   Ruby:\n\n   ```ruby\n   require 'functional/pattern_matching'\n\n   class Foo\n     include Functional::PatternMatching\n\n     defn(:greet, _) do |name|\n       \"Hello, {name}!\"\n     end\n\n     defn(:greet, :male, _) { |name|\n       \"Hello, Mr. {name}!\"\n     }\n     defn(:greet, :female, _) { |name|\n       \"Hello, Ms. {name}!\"\n     }\n     defn(:greet, nil, _) { |name|\n       \"Goodbye, {name}!\"\n     }\n     defn(:greet, _, _) { |_, name|\n       \"Hello, {name}!\"\n     }\n   end\n   ```\n\n    Constructor Overloading\n\n   ```ruby\n   require 'functional/pattern_matching'\n\n   class Foo\n     include Functional::PatternMatching\n\n     defn(:initialize) { @name = 'baz' }\n     defn(:initialize, _) {|name| @name = name.to_s }\n   end\n   ```\n\n    Matching by Class/Datatype\n\n   ```ruby\n   require 'functional/pattern_matching'\n\n   class Foo\n     include Functional::PatternMatching\n\n     defn(:concat, Integer, Integer) { |first, second|\n       first + second\n     }\n     defn(:concat, Integer, String) { |first, second|\n       \"{first} {second}\"\n     }\n     defn(:concat, String, String) { |first, second|\n       first + second\n     }\n     defn(:concat, Integer, _) { |first, second|\n       first + second.to_i\n     }\n   end\n   ```\n\n    Matching a Hash Parameter\n\n   ```ruby\n   require 'functional/pattern_matching'\n\n   class Foo\n     include Functional::PatternMatching\n\n     defn(:hashable, {foo: :bar}) { |opts|\n        matches any hash with key :foo and value :bar\n       :foo_bar\n     }\n     defn(:hashable, {foo: _, bar: _}) { |f, b|\n        matches any hash with keys :foo and :bar\n        passes the values associated with those keys to the block\n       [f, b]\n     }\n     defn(:hashable, {foo: _}) { |f|\n        matches any hash with key :foo\n        passes the value associated with that key to the block\n        must appear AFTER the prior match or it will override that one\n       f\n     }\n     defn(:hashable, {}) { |_|\n        matches an empty hash\n       :empty\n     }\n     defn(:hashable, _) { |opts|\n        matches any hash (or any other value)\n       opts\n     }\n   end\n\n   ...\n\n   foo.hashable({foo: :bar})      => :foo_bar\n   foo.hashable({foo: :baz})      => :baz\n   foo.hashable({foo: 1, bar: 2}) => [1, 2]\n   foo.hashable({foo: 1, baz: 2}) => 1\n   foo.hashable({bar: :baz})      => {bar: :baz}\n   foo.hashable({})               => :empty\n   ```\n\n    Variable Length Argument Lists with ALL\n\n   ```ruby\n   defn(:all, :one, ALL) { |args|\n     args\n   }\n   defn(:all, :one, Integer, ALL) { |int, args|\n     [int, args]\n   }\n   defn(:all, 1, _, ALL) { |var, _, *args|\n     [var, args]\n   }\n   defn(:all, ALL) { |*args|\n     args\n   }\n\n   ...\n\n   foo.all(:one, 'a', 'bee', :see) => ['a', 'bee', :see]\n   foo.all(:one, 1, 'bee', :see)   => [1, 'bee', :see]\n   foo.all(1, 'a', 'bee', :see)    => ['a', ['bee', :see]]\n   foo.all('a', 'bee', :see)       => ['a', 'bee', :see]\n   foo.all()                       => NoMethodError: no method `all` matching [] found for class Foo\n   ```\n\n#####    Guard Clauses\n\n   These examples are based on [Syntax in defnctions: Pattern Matching](http://learnyousomeerlang.com/syntax-in-defnctions)\n   in [Learn You Some Erlang for Great Good!](http://learnyousomeerlang.com/).\n\n   Erlang:\n\n   ```erlang\n   old_enough(X) when X >= 16 -> true;\n   old_enough(_) -> false.\n\n   right_age(X) when X >= 16, X =< 104 ->\n     true;\n   right_age(_) ->\n     false.\n\n   wrong_age(X) when X < 16; X > 104 ->\n     true;\n   wrong_age(_) ->\n     false.\n   ```\n\n   ```ruby\n   defn(:old_enough, _){ |_| true }.when{|x| x >= 16 }\n   defn(:old_enough, _){ |_| false }\n\n   defn(:right_age, _) { |_|\n     true\n   }.when{|x| x >= 16 && x <= 104 }\n\n   defn(:right_age, _) { |_|\n     false\n   }\n\n   defn(:wrong_age, _) { |_|\n     false\n   }.when{|x| x < 16 || x > 104 }\n\n   defn(:wrong_age, _) { |_|\n     true\n   }\n   ```\n\n###    Inspiration\n\n   Pattern matching has its roots in logic programming languages such as\n   [Prolog](http://en.wikipedia.org/wiki/Prolog). Pattern matching is a core\n   feature of the [Erlang](http://www.erlang.org/) programming language. A few\n   helpful resources are:\n\n   * Erlang [modules](http://erlang.org/doc/reference_manual/modules.html)\n   * Erlang [pattern matching](http://erlang.org/doc/reference_manual/patterns.html)\n"
  },
  {
    "path": "doc/protocol.md",
    "content": "###    Rationale\n\n   Traditional object orientation implements polymorphism inheritance. The *Is-A*\n   relationship indicates that one object \"is a\" instance of another object.\n   Implicit in this relationship, however, is the concept of [type](http://en.wikipedia.org/wiki/Data_type).\n   Every Ruby object has a *type*, and that type is the name of its `Class` or\n   `Module`. The Ruby runtime provides a number of reflective methods that allow\n   objects to be interrogated for type information. The principal of thses is the\n   `is_a?` (alias `kind_of`) method defined in class `Object`.\n\n   Unlike many traditional object oriented languages, Ruby is a [dynamically typed](http://en.wikipedia.org/wiki/Dynamic_typingDYNAMIC)\n   language. Types exist but the runtime is free to cast one type into another\n   at any time. Moreover, Ruby is a [duck typed](http://en.wikipedia.org/wiki/Duck_typing).\n   If an object \"walks like a duck and quacks like a duck then it must be a duck.\"\n   When a method needs called on an object Ruby does not check the type of the object,\n   it simply checks to see if the requested function exists with the proper\n   [arity](http://en.wikipedia.org/wiki/Arity) and, if it does, dispatches the call.\n   The duck type analogue to `is_a?` is `respond_to?`. Thus an object can be interrogated\n   for its behavior rather than its type.\n\n   Although Ruby offers several methods for reflecting on the behavior of a module/class/object,\n   such as `method`, `instance_methods`, `const_defined?`, the aforementioned `respond_to?`,\n   and others, Ruby lacks a convenient way to group collections of methods in any way that\n   does not involve type. Both modules and classes provide mechanisms for combining\n   methods into cohesive abstractions, but they both imply type. This is anathema to Ruby's\n   dynamism and duck typing. What Ruby needs is a way to collect a group of method names\n   and signatures into a cohesive collection that embraces duck typing and dynamic dispatch.\n   This is what protocols do.\n\n###    Specifying\n\n   A \"protocol\" is a loose collection of method, attribute, and constant names with optional\n   arity values. The protocol definition does very little on its own. The power of protocols\n   is that they provide a way for modules, classes, and objects to be interrogated with\n   respect to common behavior, not common type. At the core a protocol is nothing more\n   than a collection of `respond_to?` method calls that ask the question \"Does this thing\n   *behave* like this other thing.\"\n\n   Protocols are specified with the `Functional::SpecifyProtocol` method. It takes one parameter,\n   the name of the protocol, and a block which contains the protocol specification. This registers\n   the protocol specification and makes it available for use later when interrogating ojects\n   for their behavior.\n\n#####    Defining Attributes, Methods, and Constants\n\n   A single protocol specification can include definition for attributes, methods,\n   and constants. Methods and attributes can be defined as class/module methods or\n   as instance methods. Within the a protocol specification each item must include\n   the symbolic name of the item being defined.\n\n   ```ruby\n   Functional::SpecifyProtocol(:KitchenSink) do\n     instance_method     :instance_method\n     class_method        :class_method\n     attr_accessor       :attr_accessor\n     attr_reader         :attr_reader\n     attr_writer         :attr_writer\n     class_attr_accessor :class_attr_accessor\n     class_attr_reader   :class_attr_reader\n     class_attr_writer   :class_attr_writer\n     constant            :CONSTANT\n   end\n   ```\n\n   Definitions for accessors are expanded at specification into the apprporiate\n   method(s). Which means that this:\n\n   ```ruby\n   Functional::SpecifyProtocol(:Name) do\n     attr_accessor :first\n     attr_accessor :middle\n     attr_accessor :last\n     attr_accessor :suffix\n   end\n   ```\n\n   is the same as:\n\n   ```ruby\n   Functional::SpecifyProtocol(:Name) do\n     instance_method :first\n     instance_method :first=\n     instance_method :middle\n     instance_method :middle=\n     instance_method :last\n     instance_method :last=\n     instance_method :suffix\n     instance_method :suffix=\n   end\n   ```\n\n   Protocols only care about the methods themselves, not how they were declared.\n\n###    Arity\n\n   In addition to defining *which* methods exist, the required method arity can\n   indicated. Arity is optional. When no arity is given any arity will be expected.\n   The arity rules follow those defined for the `arity` method of Ruby's\n   [Method class](http://www.ruby-doc.org/core-2.1.2/Method.htmlmethod-i-arity):\n\n   * Methods with a fixed number of arguments have a non-negative arity\n   * Methods with optional arguments have an arity `-n - 1`, where n is the number of required arguments\n   * Methods with a variable number of arguments have an arity of `-1`\n\n   ```ruby\n   Functional::SpecifyProtocol(:Foo) do\n     instance_method :any_args\n     instance_method :no_args, 0\n     instance_method :three_args, 3\n     instance_method :optional_args, -2\n     instance_method :variable_args, -1\n   end\n\n   class Bar\n\n     def any_args(a, b, c=1, d=2, *args)\n     end\n\n     def no_args\n     end\n\n     def three_args(a, b, c)\n     end\n\n     def optional_args(a, b=1, c=2)\n     end\n\n     def variable_args(*args)\n     end\n   end\n   ```\n\n###    Reflection\n\n   Once a protocol has been defined, any class, method, or object may be interrogated\n   for adherence to one or more protocol specifications. The methods of the\n   `Functional::Protocol` classes provide this capability. The `Satisfy?` method\n   takes a module/class/object as the first parameter and one or more protocol names\n   as the second and subsequent parameters. It returns a boolean value indicating\n   whether the given object satisfies the protocol requirements:\n\n   ```ruby\n   Functional::SpecifyProtocol(:Queue) do\n     instance_method :push, 1\n     instance_method :pop, 0\n     instance_method :length, 0\n   end\n\n   Functional::SpecifyProtocol(:List) do\n     instance_method :[]=, 2\n     instance_method :[], 1\n     instance_method :each, 0\n     instance_method :length, 0\n   end\n\n   Functional::Protocol::Satisfy?(Queue, :Queue)        => true\n   Functional::Protocol::Satisfy?(Queue, :List)         => false\n\n   list = [1, 2, 3]\n   Functional::Protocol::Satisfy?(Array, :List, :Queue) => true\n   Functional::Protocol::Satisfy?(list, :List, :Queue)  => true\n\n   Functional::Protocol::Satisfy?(Hash, :Queue)         => false\n\n   Functional::Protocol::Satisfy?('foo bar baz', :List) => false\n   ```\n\n   The `Satisfy!` method performs the exact same check but instead raises an exception\n   when the protocol is not satisfied:\n\n   ```\n   2.1.2 :021 > Functional::Protocol::Satisfy!(Queue, :List)\n   Functional::ProtocolError: Value (Class) 'Thread::Queue' does not behave as all of: :List.\n   \tfrom /Projects/functional-ruby/lib/functional/protocol.rb:67:in `error'\n   \tfrom /Projects/functional-ruby/lib/functional/protocol.rb:36:in `Satisfy!'\n   \tfrom (irb):21\n     ...\n   ```\n   The `Functional::Protocol` module can be included within other classes\n   to eliminate the namespace requirement when calling:\n\n   ```ruby\n   class MessageFormatter\n     include Functional::Protocol\n\n     def format(message)\n       if Satisfy?(message, :Internal)\n         format_internal_message(message)\n       elsif Satisfy?(message, :Error)\n         format_error_message(message)\n       else\n         format_generic_message(message)\n       end\n     end\n\n     private\n\n     def format_internal_message(message)\n        format the message...\n     end\n\n     def format_error_message(message)\n        format the message...\n     end\n\n     def format_generic_message(message)\n        format the message...\n     end\n   ```\n\n###   Inspiration\n\n   Protocols and similar functionality exist in several other programming languages.\n   A few languages that provided inspiration for this inplementation are:\n\n   * Clojure [protocol](http://clojure.org/protocols)\n   * Erlang [behaviours](http://www.erlang.org/doc/design_principles/des_princ.htmlid60128)\n   * Objective-C [protocol](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithProtocols/WorkingwithProtocols.html)\n     (and the corresponding Swift [protocol](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html))\n"
  },
  {
    "path": "doc/record.md",
    "content": "###    Declaration\n\n   A `Record` class is declared in a manner identical to that used with Ruby's `Struct`.\n   The class method `new` is called with a list of one or more field names (symbols).\n   A new class will then be dynamically generated along with the necessary reader\n   attributes, one for each field. The newly created class will be anonymous and\n   will mixin `Functional::AbstractStruct`. The best practice is to assign the newly\n   created record class to a constant:\n\n   ```ruby\n   Customer = Functional::Record.new(:name, :address) => Customer\n   ```\n\n   Alternatively, the name of the record class, as a string, can be given as the\n   first parameter. In this case the new record class will be created as a constant\n   within the `Record` module:\n\n   ```ruby\n   Functional::Record.new(\"Customer\", :name, :address) => Functional::Record::Customer\n   ```\n\n###    Type Specification\n\n   Unlike a Ruby `Struct`, a `Record` may be declared with a type/protocol\n   specification. In this case, all data members are checked against the\n   specification whenever a new record is created. Declaring a `Record` with a\n   type specification is similar to declaring a normal `Record`, except that\n   the field list is given as a hash with field names as the keys and a class or\n   protocol as the values.\n\n   ```ruby\n   Functional::SpecifyProtocol(:Name) do\n     attr_reader :first\n     attr_reader :middle\n     attr_reader :last\n   end\n\n   TypedCustomer = Functional::Record.new(name: :Name, address: String) => TypedCustomer\n\n   Functional::Record.new(\"TypedCustomer\", name: :Name, address: String) => Functional::Record::TypedCustomer\n   ```\n\n###    Construction\n\n   Construction of a new object from a record is slightly different than for a Ruby `Struct`.\n   The constructor for a struct class may take zero or more field values and will use those\n   values to popuate the fields. The values passed to the constructor are assumed to be in\n   the same order as the fields were defined. This works for a struct because it is\n   mutable--the field values may be changed after instanciation. Therefore it is not\n   necessary to provide all values to a stuct at creation. This is not the case for a\n   record. A record is immutable. The values for all its fields must be set at instanciation\n   because they cannot be changed later. When creating a new record object the constructor\n   will accept a collection of field/value pairs in hash syntax and will create the new\n   record with the given values:\n\n   ```ruby\n   Customer.new(name: 'Dave', address: '123 Main')\n    => <record Customer :name=>\"Dave\", :address=>\"123 Main\">\n\n   Functional::Record::Customer.new(name: 'Dave', address: '123 Main')\n    => <record Functional::Record::Customer :name=>\"Dave\", :address=>\"123 Main\">\n   ```\n\n   When a record is defined with a type/protocol specification, the values of\n   all non-nil data members are checked against the specification. Any data\n   value that is not of the given type or does not satisfy the given protocol\n   will cause an exception to be raised:\n\n   ```ruby\n   class Name\n     attr_reader :first, :middle, :last\n     def initialize(first, middle, last)\n       @first = first\n       @middle = middle\n       @last = last\n     end\n   end\n\n   name = Name.new('Douglas', nil, 'Adams') => <Name:0x007fc8b951a278 ...\n   TypedCustomer.new(name: name, address: '123 Main') => <record TypedCustomer :name=><Name:0x007f914cce05b0 ...\n\n   TypedCustomer.new(name: 'Douglas Adams', address: '123 Main') => ArgumentError: 'name' must stasify the protocol :Name\n   TypedCustomer.new(name: name, address: 42) => ArgumentError: 'address' must be of type String\n   ```\n\n###    Default Values\n\n   By default, all record fields are set to `nil` at instanciation unless explicity set\n   via the constructor. It is possible to specify default values other than `nil` for\n   zero or more of the fields when a new record class is created. The `new` method of\n   `Record` accepts a block which can be used to declare new default values:\n\n   ```ruby\n   Address = Functional::Record.new(:street_line_1, :street_line_2,\n                                    :city, :state, :postal_code, :country) do\n     default :state, 'Ohio'\n     default :country, 'USA'\n   end\n    => Address\n   ```\n\n   When a new object is created from a record class with explicit default values, those\n   values will be used for the appropriate fields when no other value is given at\n   construction:\n\n   ```ruby\n   Address.new(street_line_1: '2401 Ontario St',\n               city: 'Cleveland', postal_code: 44115)\n    => <record Address :street_line_1=>\"2401 Ontario St\", :street_line_2=>nil, :city=>\"Cleveland\", :state=>\"Ohio\", :postal_code=>44115, :country=>\"USA\">\n   ```\n\n   Of course, if a value for a field is given at construction that value will be used instead\n   of the custom default:\n\n   ```ruby\n   Address.new(street_line_1: '1060 W Addison St',\n               city: 'Chicago', state: 'Illinois', postal_code: 60613)\n    => <record Address :street_line_1=>\"1060 W Addison St\", :street_line_2=>nil, :city=>\"Chicago\", :state=>\"Illinois\", :postal_code=>60613, :country=>\"USA\">\n   ```\n\n###    Mandatory Fields\n\n   By default, all record fields are optional. It is perfectly legal for a record\n   object to exist with all its fields set to `nil`. During declaration of a new record\n   class the block passed to `Record.new` can also be used to indicate which fields\n   are mandatory. When a new object is created from a record with mandatory fields\n   an exception will be thrown if any of those fields are nil:\n\n   ```ruby\n   Name = Functional::Record.new(:first, :middle, :last, :suffix) do\n     mandatory :first, :last\n   end\n    => Name\n\n   Name.new(first: 'Joe', last: 'Armstrong')\n    => <record Name :first=>\"Joe\", :middle=>nil, :last=>\"Armstrong\", :suffix=>nil>\n\n   Name.new(first: 'Matz') => ArgumentError: mandatory fields must not be nil\n   ```\n\n   Of course, declarations for default values and mandatory fields may be used\n   together:\n\n   ```ruby\n   Person = Functional::Record.new(:first_name, :middle_name, :last_name,\n                                   :street_line_1, :street_line_2,\n                                   :city, :state, :postal_code, :country) do\n     mandatory :first_name, :last_name\n     mandatory :country\n     default :state, 'Ohio'\n     default :country, 'USA'\n   end\n    => Person\n   ```\n\n###    Default Value Memoization\n\n   Note that the block provided to `Record.new` is processed once and only once\n   when the new record class is declared. Thereafter the results are memoized\n   and copied (via `clone`, unless uncloneable) each time a new record object\n   is created. Default values should be simple types like `String`, `Fixnum`,\n   and `Boolean`. If complex operations need performed when setting default\n   values the a `Class` should be used instead of a `Record`.\n\n#####    Why Declaration Differs from Ruby's Struct\n\n   Those familiar with Ruby's `Struct` class will notice one important\n   difference when declaring a `Record`: the block passes to `new` cannot be\n   used to define additional methods. When declaring a new class created from a\n   Ruby `Struct` the block can perform any additional class definition that\n   could be done had the class be defined normally. The excellent\n   [Values](https://github.com/tcrayford/Values) supports this same behavior.\n   `Record` does not allow additional class definitions during declaration for\n   one simple reason: doing so violates two very important tenets of functional\n   programming. Specifically, immutability and the separation of data from\n   operations.\n\n   `Record` exists for the purpose of creating immutable objects. If additional\n   instance methods were to be defined on a record class it would be possible\n   to violate immutability. Not only could additional, mutable state be added\n   to the class, but the existing immutable attributes could be overridden by\n   mutable methods. The security of providing an immutable object would be\n   completely shattered, thus defeating the original purpose of the record\n   class. Of course it would be possible to allow this feature and trust the\n   programmer to not violate the intended immutability of class, but opening\n   `Record` to the *possibility* of immutability violation is unnecessary and\n   unwise.\n\n   More important than the potential for immutability violations is the fact\n   the adding additional methods to a record violates the principal of\n   separating data from operations on that data. This is one of the core ideas\n   in functional programming. Data is defined in pure structures that contain\n   no behavior and operations on that data are provided by polymorphic\n   functions. This may seem counterintuitive to object oriented programmers,\n   but that is the nature of functional programming. Adding behavior to a\n   record, even when that behavior does not violate immutability, is still\n   anathema to functional programming, and it is why records in languages like\n   Erlang and Clojure do not have functions defined within them.\n\n   Should additional methods need defined on a `Record` class, the appropriate\n   practice is to declare the record class then declare another class which\n   extends the record. The record class remains pure data and the subclass\n   contains additional operations on that data.\n\n   ```ruby\n   NameRecord = Functional::Record.new(:first, :middle, :last, :suffix) do\n     mandatory :first, :last\n   end\n\n   class Name < NameRecord\n     def full_name\n       \"{first} {last}\"\n     end\n\n     def formal_name\n       name = [first, middle, last].select{|s| ! s.to_s.empty?}.join(' ')\n       suffix.to_s.empty? ? name : name + \", {suffix}\"\n     end\n   end\n\n   jerry = Name.new(first: 'Jerry', last: \"D'Antonio\")\n   ted   = Name.new(first: 'Ted', middle: 'Theodore', last: 'Logan', suffix: 'Esq.')\n\n   jerry.formal_name => \"Jerry D'Antonio\"\n   ted.formal_name   => \"Ted Theodore Logan, Esq.\"\n   ```\n\n###    Inspiration\n\n   Neither struct nor records are new to computing. Both have been around for a very\n   long time. Mutable structs can be found in many languages including\n   [Ruby](http://www.ruby-doc.org/core-2.1.2/Struct.html),\n   [Go](http://golang.org/ref/specStruct_types),\n   [C](http://en.wikipedia.org/wiki/Struct_(C_programming_language)),\n   and [C](http://msdn.microsoft.com/en-us/library/ah19swz4.aspx),\n   just to name a few. Immutable records exist primarily in functional languages\n   like [Haskell](http://en.wikibooks.org/wiki/Haskell/More_on_datatypesNamed_Fields_.28Record_Syntax.29),\n   Clojure, and Erlang. The inspiration for declaring records with a type\n   specification is taken from [PureScript](http://www.purescript.org/), a\n   compile-to-JavaScript language inspired by Haskell.\n\n   * [Ruby Struct](http://www.ruby-doc.org/core-2.1.2/Struct.html)\n   * [Clojure Datatypes](http://clojure.org/datatypes)\n   * [Clojure *defrecord* macro](http://clojure.github.io/clojure/clojure.core-api.htmlclojure.core/defrecord)\n   * [Erlang Records (Reference)](http://www.erlang.org/doc/reference_manual/records.html)\n   * [Erlang Records (Examples)](http://www.erlang.org/doc/programming_examples/records.html)\n   * [PureScript Records](http://docs.purescript.org/en/latest/types.htmlrecords)\n"
  },
  {
    "path": "functional_ruby.gemspec",
    "content": "$LOAD_PATH << File.expand_path('../lib', __FILE__)\n\nrequire 'functional/version'\n\nGem::Specification.new do |s|\n  s.name        = 'functional-ruby'\n  s.version     = Functional::VERSION\n  s.platform    = Gem::Platform::RUBY\n  s.author      = \"Jerry D'Antonio\"\n  s.email       = 'jerry.dantonio@gmail.com'\n  s.homepage    = 'https://github.com/jdantonio/functional-ruby/'\n  s.summary     = 'Erlang, Clojure, Haskell, and Functional Java inspired functional programming tools for Ruby.'\n  s.license     = 'MIT'\n  s.date        = Time.now.strftime('%Y-%m-%d')\n\n  s.description = <<-EOF\n    A gem for adding functional programming tools to Ruby. Inspired by Erlang, Clojure, Haskell, and Functional Java.\n  EOF\n\n  s.files             = Dir['README*', 'LICENSE*', 'CHANGELOG*']\n  s.files            += Dir['{lib}/**/*']\n  s.test_files        = Dir['{spec}/**/*']\n  s.extra_rdoc_files  = Dir['README*', 'LICENSE*', 'CHANGELOG*']\n  s.extra_rdoc_files += Dir['{doc}/**/*.{txt,md}']\n  s.require_paths     = ['lib']\n\n  s.required_ruby_version = '>= 2.0.0'\nend\n"
  },
  {
    "path": "lib/functional/abstract_struct.rb",
    "content": "require 'functional/protocol'\nrequire 'functional/synchronization'\n\nFunctional::SpecifyProtocol(:Struct) do\n  instance_method :fields\n  instance_method :values\n  instance_method :length\n  instance_method :each\n  instance_method :each_pair\nend\n\nmodule Functional\n\n  # An abstract base class for immutable struct classes.\n  # @!visibility private\n  module AbstractStruct\n\n    # @return [Array] the values of all record fields in order, frozen\n    attr_reader :values\n\n    # Yields the value of each record field in order.\n    # If no block is given an enumerator is returned.\n    #\n    # @yieldparam [Object] value the value of the given field\n    #\n    # @return [Enumerable] when no block is given\n    def each\n      return enum_for(:each) unless block_given?\n      fields.each do |field|\n        yield(self.send(field))\n      end\n    end\n\n    # Yields the name and value of each record field in order.\n    # If no block is given an enumerator is returned.\n    #\n    # @yieldparam [Symbol] field the record field for the current iteration\n    # @yieldparam [Object] value the value of the current field\n    #\n    # @return [Enumerable] when no block is given\n    def each_pair\n      return enum_for(:each_pair) unless block_given?\n      fields.each do |field|\n        yield(field, self.send(field))\n      end\n    end\n\n    # Equality--Returns `true` if `other` has the same record subclass and has equal\n    # field values (according to `Object#==`).\n    #\n    # @param [Object] other the other record to compare for equality\n    # @return [Boolean] true when equal else false\n    def eql?(other)\n      self.class == other.class && self.to_h == other.to_h\n    end\n    alias_method :==, :eql?\n\n    # @!macro [attach] inspect_method\n    #\n    #   Describe the contents of this struct in a string. Will include the name of the\n    #   record class, all fields, and all values.\n    #\n    #   @return [String] the class and contents of this record\n    def inspect\n      state = to_h.to_s.gsub(/^{/, '').gsub(/}$/, '')\n      \"#<#{self.class.datatype} #{self.class} #{state}>\"\n    end\n    alias_method :to_s, :inspect\n\n    # Returns the number of record fields.\n    #\n    # @return [Fixnum] the number of record fields\n    def length\n      fields.length\n    end\n    alias_method :size, :length\n\n    # A frozen array of all record fields.\n    #\n    # @return [Array] all record fields in order, frozen\n    def fields\n      self.class.fields\n    end\n\n    # Returns a Hash containing the names and values for the record’s fields.\n    #\n    # @return [Hash] collection of all fields and their associated values\n    def to_h\n      @data\n    end\n\n    protected\n\n    # Set the internal data hash to a copy of the given hash and freeze it.\n    # @param [Hash] data the data hash\n    #\n    # @!visibility private\n    def set_data_hash(data)\n      @data = data.dup.freeze\n    end\n\n    # Set the internal values array to a copy of the given array and freeze it.\n    # @param [Array] values the values array\n    #\n    # @!visibility private\n    def set_values_array(values)\n      @values = values.dup.freeze\n    end\n\n    # Define a new struct class and, if necessary, register it with\n    # the calling class/module. Will also set the datatype and fields\n    # class attributes on the new struct class.\n    #\n    # @param [Module] parent the class/module that is defining the new struct\n    # @param [Symbol] datatype the datatype value for the new struct class\n    # @param [Array] fields the list of symbolic names for all data fields\n    # @return [Functional::AbstractStruct, Array] the new class and the\n    #   (possibly) updated fields array\n    #\n    # @!visibility private\n    def self.define_class(parent, datatype, fields)\n      struct = Class.new(Functional::Synchronization::Object){ include AbstractStruct }\n      if fields.first.is_a? String\n        parent.const_set(fields.first, struct)\n        fields = fields[1, fields.length-1]\n      end\n      fields = fields.collect{|field| field.to_sym }.freeze\n      struct.send(:datatype=, datatype.to_sym)\n      struct.send(:fields=, fields)\n      [struct, fields]\n    end\n\n    private\n\n    def self.included(base)\n      base.extend(ClassMethods)\n      super(base)\n    end\n\n    # Class methods added to a class that includes {Functional::PatternMatching}\n    #\n    # @!visibility private\n    module ClassMethods\n\n      # A frozen Array of all record fields in order\n      attr_reader :fields\n\n      # A symbol describing the object's datatype\n      attr_reader :datatype\n\n      private\n\n      # A frozen Array of all record fields in order\n      attr_writer :fields\n\n      # A symbol describing the object's datatype\n      attr_writer :datatype\n\n      fields = [].freeze\n      datatype = :struct\n    end\n  end\nend\n"
  },
  {
    "path": "lib/functional/delay.rb",
    "content": "require 'functional/synchronization'\n\nmodule Functional\n\n  # Lazy evaluation of a block yielding an immutable result. Useful for\n  # expensive operations that may never be needed.\n  #\n  # When a `Delay` is created its state is set to `pending`. The value and\n  # reason are both `nil`. The first time the `#value` method is called the\n  # enclosed opration will be run and the calling thread will block. Other\n  # threads attempting to call `#value` will block as well. Once the operation\n  # is complete the *value* will be set to the result of the operation or the\n  # *reason* will be set to the raised exception, as appropriate. All threads\n  # blocked on `#value` will return. Subsequent calls to `#value` will\n  # immediately return the cached value. The operation will only be run once.\n  # This means that any side effects created by the operation will only happen\n  # once as well.\n  #\n  # @!macro [new] thread_safe_immutable_object\n  #\n  #    @note This is a write-once, read-many, thread safe object that can be\n  #      used in concurrent systems. Thread safety guarantees *cannot* be made\n  #      about objects contained *within* this object, however. Ruby variables\n  #      are mutable references to mutable objects. This cannot be changed. The\n  #      best practice it to only encapsulate immutable, frozen, or thread safe\n  #      objects. Ultimately, thread safety is the responsibility of the\n  #      programmer.\n  #\n  # @see http://clojuredocs.org/clojure_core/clojure.core/delay Clojure delay\n  class Delay < Synchronization::Object\n\n    # Create a new `Delay` in the `:pending` state.\n    #\n    # @yield the delayed operation to perform\n    #\n    # @raise [ArgumentError] if no block is given\n    def initialize(&block)\n      raise ArgumentError.new('no block given') unless block_given?\n      super\n      synchronize do\n        @state = :pending\n        @task  = block\n      end\n    end\n\n    # Current state of block processing.\n    #\n    # @return [Symbol] the current state of block processing\n    def state\n      synchronize{ @state }\n    end\n\n    # The exception raised when processing the block. Returns `nil` if the\n    # operation is still `:pending` or has been `:fulfilled`.\n    #\n    # @return [StandardError] the exception raised when processing the block\n    #   else nil.\n    def reason\n      synchronize{ @reason }\n    end\n\n    # Return the (possibly memoized) value of the delayed operation.\n    #\n    # If the state is `:pending` then the calling thread will block while the\n    # operation is performed. All other threads simultaneously calling `#value`\n    # will block as well. Once the operation is complete (either `:fulfilled` or\n    # `:rejected`) all waiting threads will unblock and the new value will be\n    # returned.\n    #\n    # If the state is not `:pending` when `#value` is called the (possibly\n    # memoized) value will be returned without blocking and without performing\n    # the operation again.\n    #\n    # @return [Object] the (possibly memoized) result of the block operation\n    def value\n      synchronize{ execute_task_once }\n    end\n\n    # Has the delay been fulfilled?\n    # @return [Boolean]\n    def fulfilled?\n      synchronize{ @state == :fulfilled }\n    end\n    alias_method :value?, :fulfilled?\n\n    # Has the delay been rejected?\n    # @return [Boolean]\n    def rejected?\n      synchronize{ @state == :rejected }\n    end\n    alias_method :reason?, :rejected?\n\n    # Is delay completion still pending?\n    # @return [Boolean]\n    def pending?\n      synchronize{ @state == :pending }\n    end\n\n    protected\n\n    # @!visibility private\n    #\n    # Execute the enclosed task then cache and return the result if the current\n    # state is pending. Otherwise, return the cached result.\n    #\n    # @return [Object] the result of the block operation\n    def execute_task_once\n      if @state == :pending\n        begin\n          @value = @task.call\n          @state = :fulfilled\n        rescue => ex\n          @reason = ex\n          @state  = :rejected\n        end\n      end\n      @value\n    end\n  end\nend\n"
  },
  {
    "path": "lib/functional/either.rb",
    "content": "require 'functional/abstract_struct'\nrequire 'functional/protocol'\nrequire 'functional/synchronization'\n\nFunctional::SpecifyProtocol(:Either) do\n  instance_method :left, 0\n  instance_method :left?, 0\n  instance_method :right, 0\n  instance_method :right?, 0\nend\n\nmodule Functional\n\n  # The `Either` type represents a value of one of two possible types (a\n  # disjoint union). It is an immutable structure that contains one and only one\n  # value. That value can be stored in one of two virtual position, `left` or\n  # `right`. The position provides context for the encapsulated data.\n  #\n  # One of the main uses of `Either` is as a return value that can indicate\n  # either success or failure. Object oriented programs generally report errors\n  # through either state or exception handling, neither of which work well in\n  # functional programming. In the former case, a method is called on an object\n  # and when an error occurs the state of the object is updated to reflect the\n  # error. This does not translate well to functional programming because they\n  # eschew state and mutable objects. In the latter, an exception handling block\n  # provides branching logic when an exception is thrown. This does not\n  # translate well to functional programming because it eschews side effects\n  # like structured exception handling (and structured exception handling tends\n  # to be very expensive). `Either` provides a powerful and easy-to-use\n  # alternative.\n  #\n  # A function that may generate an error can choose to return an immutable\n  # `Either` object in which the position of the value (left or right) indicates\n  # the nature of the data. By convention, a `left` value indicates an error and\n  # a `right` value indicates success. This leaves the caller with no ambiguity\n  # regarding success or failure, requires no persistent state, and does not\n  # require expensive exception handling facilities.\n  #\n  # `Either` provides several aliases and convenience functions to facilitate\n  # these failure/success conventions. The `left` and `right` functions,\n  # including their derivatives, are mirrored by `reason` and `value`. Failure\n  # is indicated by the presence of a `reason` and success is indicated by the\n  # presence of a `value`. When an operation has failed the either is in a\n  # `rejected` state, and when an operation has successed the either is in a\n  # `fulfilled` state. A common convention is to use a Ruby `Exception` as the\n  # `reason`. The factory method `error` facilitates this. The semantics and\n  # conventions of `reason`, `value`, and their derivatives follow the\n  # conventions of the Concurrent Ruby gem.\n  #\n  # The `left`/`right` and `reason`/`value` methods are not mutually exclusive.\n  # They can be commingled and still result in functionally correct code. This\n  # practice should be avoided, however. Consistent use of either `left`/`right`\n  # or `reason`/`value` against each `Either` instance will result in more\n  # expressive, intent-revealing code.\n  #\n  # @example\n  #\n  #   require 'uri'\n  #\n  #   def web_host(url)\n  #     uri = URI(url)\n  #     if uri.scheme != 'http'\n  #       Functional::Either.left('Invalid HTTP URL')\n  #     else\n  #       Functional::Either.right(uri.host)\n  #     end\n  #   end\n  #\n  #   good = web_host('http://www.concurrent-ruby.com')\n  #   good.right? #=> true\n  #   good.right  #=> \"www.concurrent-ruby\"\n  #   good.left #=> nil\n  #\n  #   good = web_host('bogus')\n  #   good.right? #=> false\n  #   good.right  #=> nil\n  #   good.left #=> \"Invalid HTTP URL\"\n  #\n  # @see http://functionaljava.googlecode.com/svn/artifacts/3.0/javadoc/fj/data/Either.html Functional Java\n  # @see https://hackage.haskell.org/package/base-4.2.0.1/docs/Data-Either.html Haskell Data.Either\n  # @see http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Obligation.html Concurrent Ruby\n  #\n  # @!macro thread_safe_immutable_object\n  class Either < Synchronization::Object\n    include AbstractStruct\n\n    self.datatype = :either\n    self.fields = [:left, :right].freeze\n\n    # @!visibility private\n    NO_VALUE = Object.new.freeze\n\n    private_class_method :new\n\n    class << self\n\n      # Construct a left value of either.\n      #\n      # @param [Object] value The value underlying the either.\n      # @return [Either] A new either with the given left value.\n      def left(value)\n        new(value, true).freeze\n      end\n      alias_method :reason, :left\n\n      # Construct a right value of either.\n      #\n      # @param [Object] value The value underlying the either.\n      # @return [Either] A new either with the given right value.\n      def right(value)\n        new(value, false).freeze\n      end\n      alias_method :value, :right\n\n      # Create an `Either` with the left value set to an `Exception` object\n      # complete with message and backtrace. This is a convenience method for\n      # supporting the reason/value convention with the reason always being\n      # an `Exception` object. When no exception class is given `StandardError`\n      # will be used. When no message is given the default message for the\n      # given error class will be used.\n      #\n      # @example\n      #\n      #   either = Functional::Either.error(\"You're a bad monkey, Mojo Jojo\")\n      #   either.fulfilled? #=> false\n      #   either.rejected?  #=> true\n      #   either.value      #=> nil\n      #   either.reason     #=> #<StandardError: You're a bad monkey, Mojo Jojo>\n      #\n      # @param [String] message The message for the new error object.\n      # @param [Exception] clazz The class for the new error object.\n      # @return [Either] A new either with an error object as the left value.\n      def error(message = nil, clazz = StandardError)\n        ex = clazz.new(message)\n        ex.set_backtrace(caller)\n        left(ex)\n      end\n    end\n\n    # Projects this either as a left.\n    #\n    # @return [Object] The left value or `nil` when `right`.\n    def left\n      left? ? to_h[:left] : nil\n    end\n    alias_method :reason, :left\n\n    # Projects this either as a right.\n    #\n    # @return [Object] The right value or `nil` when `left`.\n    def right\n      right? ? to_h[:right] : nil\n    end\n    alias_method :value, :right\n\n    # Returns true if this either is a left, false otherwise.\n    #\n    # @return [Boolean] `true` if this either is a left, `false` otherwise.\n    def left?\n      @is_left\n    end\n    alias_method :reason?, :left?\n    alias_method :rejected?, :left?\n\n    # Returns true if this either is a right, false otherwise.\n    #\n    # @return [Boolean] `true` if this either is a right, `false` otherwise.\n    def right?\n      ! left?\n    end\n    alias_method :value?, :right?\n    alias_method :fulfilled?, :right?\n\n    # If this is a left, then return the left value in right, or vice versa.\n    #\n    # @return [Either] The value of this either swapped to the opposing side.\n    def swap\n      if left?\n        self.class.send(:new, left, false)\n      else\n        self.class.send(:new, right, true)\n      end\n    end\n\n    # The catamorphism for either. Folds over this either breaking into left or right.\n    #\n    # @param [Proc] lproc The function to call if this is left.\n    # @param [Proc] rproc The function to call if this is right.\n    # @return [Object] The reduced value.\n    def either(lproc, rproc)\n      left? ? lproc.call(left) : rproc.call(right)\n    end\n\n    # If the condition satisfies, return the given A in left, otherwise, return the given B in right.\n    #\n    # @param [Object] lvalue The left value to use if the condition satisfies.\n    # @param [Object] rvalue The right value to use if the condition does not satisfy.\n    # @param [Boolean] condition The condition to test (when no block given).\n    # @yield The condition to test (when no condition given).\n    #\n    # @return [Either] A constructed either based on the given condition.\n    #\n    # @raise [ArgumentError] When both a condition and a block are given.\n    def self.iff(lvalue, rvalue, condition = NO_VALUE)\n      raise ArgumentError.new('requires either a condition or a block, not both') if condition != NO_VALUE && block_given?\n      condition = block_given? ? yield : !! condition\n      condition ? left(lvalue) : right(rvalue)\n    end\n\n    private\n\n    # Create a new Either wil the given value and disposition.\n    #\n    # @param [Object] value the value of this either\n    # @param [Boolean] is_left is this a left either or right?\n    #\n    # @!visibility private\n    def initialize(value, is_left)\n      super\n      @is_left = is_left\n      hsh = is_left ? {left: value, right: nil} : {left: nil, right: value}\n      set_data_hash(hsh)\n      set_values_array(hsh.values)\n      ensure_ivar_visibility!\n    end\n  end\nend\n"
  },
  {
    "path": "lib/functional/final_struct.rb",
    "content": "require 'functional/final_var'\nrequire 'functional/synchronization'\n\nmodule Functional\n\n  # A variation on Ruby's `OpenStruct` in which all fields are \"final\" (meaning\n  # that new fields can be arbitrarily added to a `FinalStruct` object but once\n  # set each field becomes immutable). Additionally, predicate methods exist for\n  # all fields and these predicates indicate if the field has been set.\n  #\n  # There are two ways to initialize a `FinalStruct`: with zero arguments or\n  # with a `Hash` (or any other object that implements a `to_h` method). The\n  # only difference in behavior is that a `FinalStruct` initialized with a\n  # hash will pre-define and pre-populate attributes named for the hash keys\n  # and with values corresponding to the hash values.\n  #\n  # @example Instanciation With No Fields\n  #   bucket = Functional::FinalStruct.new\n  #\n  #   bucket.foo      #=> nil\n  #   bucket.foo?     #=> false\n  #\n  #   bucket.foo = 42 #=> 42\n  #   bucket.foo      #=> 42\n  #   bucket.foo?     #=> true\n  #\n  #   bucket.foo = 42 #=> Functional::FinalityError: final accessor 'bar' has already been set\n  #\n  # @example Instanciation With a Hash\n  #   name = Functional::FinalStruct.new(first: 'Douglas', last: 'Adams')\n  #\n  #   name.first           #=> 'Douglas'\n  #   name.last            #=> 'Adams'\n  #   name.first?          #=> true\n  #   name.last?           #=> true\n  #\n  #   name.middle #=> nil\n  #   name.middle?         #=> false\n  #   name.middle = 'Noel' #=> 'Noel'\n  #   name.middle?         #=> true\n  #\n  #   name.first = 'Sam'   #=> Functional::FinalityError: final accessor 'first' has already been set\n  #\n  # @see http://www.ruby-doc.org/stdlib-2.1.2/libdoc/ostruct/rdoc/OpenStruct.html\n  # @see http://en.wikipedia.org/wiki/Final_(Java) Java `final` keyword\n  #\n  # @!macro thread_safe_final_object\n  class FinalStruct < Synchronization::Object\n\n    # Creates a new `FinalStruct` object. By default, the resulting `FinalStruct`\n    # object will have no attributes. The optional hash, if given, will generate\n    # attributes and values (can be a `Hash` or any object with a `to_h` method).\n    #\n    # @param [Hash] attributes the field/value pairs to set on creation\n    def initialize(attributes = {})\n      raise ArgumentError.new('attributes must be given as a hash or not at all') unless attributes.respond_to?(:to_h)\n      super\n      synchronize do\n        @attribute_hash = {}\n        attributes.to_h.each_pair do |field, value|\n          ns_set_attribute(field, value)\n        end\n      end\n    end\n\n    # @!macro [attach] final_struct_get_method\n    #\n    #   Get the value of the given field.\n    #\n    #   @param [Symbol] field the field to retrieve the value for\n    #   @return [Object] the value of the field is set else nil\n    def get(field)\n      synchronize { ns_get_attribute(field) }\n    end\n    alias_method :[], :get\n\n    # @!macro [attach] final_struct_set_method\n    #\n    #   Set the value of the give field to the given value.\n    #\n    #   It is a logical error to attempt to set a `final` field more than once, as this\n    #   violates the concept of finality. Calling the method a second or subsequent time\n    #   for a given field will result in an exception being raised.\n    #\n    #   @param [Symbol] field the field to set the value for\n    #   @param [Object] value the value to set the field to\n    #   @return [Object] the final value of the given field\n    #\n    # @raise [Functional::FinalityError] if the given field has already been set\n    def set(field, value)\n      synchronize do\n        if ns_attribute_has_been_set?(field)\n          raise FinalityError.new(\"final accessor '#{field}' has already been set\")\n        else\n          ns_set_attribute(field, value)\n        end\n      end\n    end\n    alias_method :[]=, :set\n\n    # @!macro [attach] final_struct_set_predicate\n    #\n    #   Check the internal hash to unambiguously verify that the given\n    #   attribute has been set.\n    #\n    #   @param [Symbol] field the field to get the value for\n    #   @return [Boolean] true if the field has been set else false\n    def set?(field)\n      synchronize { ns_attribute_has_been_set?(field) }\n    end\n\n    # Get the current value of the given field if already set else set the value of\n    # the given field to the given value.\n    #\n    # @param [Symbol] field the field to get or set the value for\n    # @param [Object] value the value to set the field to when not previously set\n    # @return [Object] the final value of the given field\n    def get_or_set(field, value)\n      synchronize { ns_attribute_has_been_set?(field) ? ns_get_attribute(field) : ns_set_attribute(field, value) }\n    end\n\n    # Get the current value of the given field if already set else return the given\n    # default value.\n    #\n    # @param [Symbol] field the field to get the value for\n    # @param [Object] default the value to return if the field has not been set\n    # @return [Object] the value of the given field else the given default value\n    def fetch(field, default)\n      synchronize { ns_attribute_has_been_set?(field) ? ns_get_attribute(field) : default }\n    end\n\n    # Calls the block once for each attribute, passing the key/value pair as parameters.\n    # If no block is given, an enumerator is returned instead.\n    #\n    # @yieldparam [Symbol] field the struct field for the current iteration\n    # @yieldparam [Object] value the value of the current field\n    #\n    # @return [Enumerable] when no block is given\n    def each_pair\n      return enum_for(:each_pair) unless block_given?\n      synchronize do\n        @attribute_hash.each do |field, value|\n          yield(field, value)\n        end\n      end\n    end\n\n    # Converts the `FinalStruct` to a `Hash` with keys representing each attribute\n    # (as symbols) and their corresponding values.\n    # \n    # @return [Hash] a `Hash` representing this struct\n    def to_h\n      synchronize { @attribute_hash.dup }\n    end\n\n    # Compares this object and other for equality. A `FinalStruct` is `eql?` to\n    # other when other is a `FinalStruct` and the two objects have identical\n    # fields and values.\n    #\n    # @param [Object] other the other record to compare for equality\n    # @return [Boolean] true when equal else false\n    def eql?(other)\n      other.is_a?(self.class) && to_h == other.to_h\n    end\n    alias_method :==, :eql?\n\n    # Describe the contents of this object in a string.\n    #\n    # @return [String] the string representation of this object\n    #\n    # @!visibility private\n    def inspect\n      state = to_h.to_s.gsub(/^{/, '').gsub(/}$/, '')\n      \"#<#{self.class} #{state}>\"\n    end\n    alias_method :to_s, :inspect\n\n    protected\n\n    # @!macro final_struct_get_method\n    # @!visibility private\n    def ns_get_attribute(field)\n      @attribute_hash[field.to_sym]\n    end\n\n    # @!macro final_struct_set_method\n    # @!visibility private\n    def ns_set_attribute(field, value)\n      @attribute_hash[field.to_sym] = value\n    end\n\n    # @!macro final_struct_set_predicate\n    # @!visibility private\n    def ns_attribute_has_been_set?(field)\n      @attribute_hash.has_key?(field.to_sym)\n    end\n\n    # Check the method name and args for signatures matching potential\n    # final attribute reader, writer, and predicate methods. If the signature\n    # matches a reader or predicate, treat the attribute as unset. If the\n    # signature matches a writer, attempt to set the new attribute.\n    #\n    # @param [Symbol] symbol the name of the called function\n    # @param [Array] args zero or more arguments\n    # @return [Object] the result of the proxied method or the `super` call\n    #\n    # @!visibility private\n    def method_missing(symbol, *args)\n      if args.length == 1 && (match = /([^=]+)=$/.match(symbol))\n        set(match[1], args.first)\n      elsif args.length == 0 && (match = /([^\\?]+)\\?$/.match(symbol))\n        set?(match[1])\n      elsif args.length == 0\n        get(symbol)\n      else\n        super\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/functional/final_var.rb",
    "content": "require 'functional/synchronization'\n\nmodule Functional\n\n  # An exception raised when an attempt is made to modify an\n  # immutable object or attribute.\n  FinalityError = Class.new(StandardError)\n\n  # A thread safe object that holds a single value and is \"final\" (meaning\n  # that the value can be set at most once after which it becomes immutable).\n  # The value can be set at instantiation which will result in the object\n  # becoming fully and immediately immutable. Attempting to set the value\n  # once it has been set is a logical error and will result in an exception\n  # being raised.\n  #\n  # @example Instanciation With No Value\n  #   f = Functional::FinalVar.new\n  #     #=> #<Functional::FinalVar unset>\n  #   f.set?       #=> false\n  #   f.value      #=> nil\n  #   f.value = 42 #=> 42\n  #   f.inspect\n  #     #=> \"#<Functional::FinalVar value=42>\"\n  #   f.set?       #=> true\n  #   f.value      #=> 42\n  #\n  # @example Instanciation With an Initial Value\n  #   f = Functional::FinalVar.new(42)\n  #     #=> #<Functional::FinalVar value=42>\n  #   f.set?       #=> true\n  #   f.value      #=> 42\n  #\n  # @see Functional::FinalStruct\n  # @see http://en.wikipedia.org/wiki/Final_(Java) Java `final` keyword\n  #\n  # @!macro [new] thread_safe_final_object\n  #\n  #   @note This is a write-once, read-many, thread safe object that can\n  #     be used in concurrent systems. Thread safety guarantees *cannot* be made\n  #     about objects contained *within* this object, however. Ruby variables are\n  #     mutable references to mutable objects. This cannot be changed. The best\n  #     practice it to only encapsulate immutable, frozen, or thread safe objects.\n  #     Ultimately, thread safety is the responsibility of the programmer.\n  class FinalVar < Synchronization::Object\n\n    # @!visibility private\n    NO_VALUE = Object.new.freeze\n\n    # Create a new `FinalVar` with the given value or \"unset\" when\n    # no value is given.\n    #\n    # @param [Object] value if given, the immutable value of the object\n    def initialize(value = NO_VALUE)\n      super\n      synchronize{ @value = value }\n    end\n\n    # Get the current value or nil if unset.\n    #\n    # @return [Object] the current value or nil\n    def get\n      synchronize { has_been_set? ? @value : nil }\n    end\n    alias_method :value, :get\n\n    # Set the value. Will raise an exception if already set.\n    #\n    # @param [Object] value the value to set\n    # @return [Object] the new value\n    # @raise [Functional::FinalityError] if the value has already been set\n    def set(value)\n      synchronize do\n        if has_been_set?\n          raise FinalityError.new('value has already been set')\n        else\n          @value = value\n        end\n      end\n    end\n    alias_method :value=, :set\n\n    # Has the value been set?\n    #\n    # @return [Boolean] true when the value has been set else false\n    def set?\n      synchronize { has_been_set? }\n    end\n    alias_method :value?, :set?\n\n    # Get the value if it has been set else set the value.\n    #\n    # @param [Object] value the value to set\n    # @return [Object] the current value if already set else the new value\n    def get_or_set(value)\n      synchronize do\n        if has_been_set?\n          @value\n        else\n          @value = value\n        end\n      end\n    end\n\n    # Get the value if set else return the given default value.\n    #\n    # @param [Object] default the value to return if currently unset\n    # @return [Object] the current value when set else the given default\n    def fetch(default)\n      synchronize { has_been_set? ? @value : default }\n    end\n\n    # Compares this object and other for equality. A `FinalVar` that is unset\n    # is never equal to anything else (it represents a complete absence of value).\n    # When set a `FinalVar` is equal to another `FinalVar` if they have the same\n    # value. A `FinalVar` is equal to another object if its value is equal to\n    # the other object using Ruby's normal equality rules.\n    #\n    # @param [Object] other the object to compare equality to\n    # @return [Boolean] true if equal else false\n    def eql?(other)\n      if (val = fetch(NO_VALUE)) == NO_VALUE\n        false\n      elsif other.is_a?(FinalVar)\n        val == other.value\n      else\n        val == other\n      end\n    end\n    alias_method :==, :eql?\n\n    # Describe the contents of this object in a string.\n    #\n    # @return [String] the string representation of this object\n    #\n    # @!visibility private\n    def inspect\n      if (val = fetch(NO_VALUE)) == NO_VALUE\n        val = 'unset'\n      else\n        val = \"value=#{val.is_a?(String) ? ('\"' + val + '\"') : val }\"\n      end\n      \"#<#{self.class} #{val}>\"\n    end\n\n    # Describe the contents of this object in a string.\n    #\n    # @return [String] the string representation of this object\n    #\n    # @!visibility private\n    def to_s\n      value.to_s\n    end\n\n    private\n\n    # Checks the set status without locking the mutex.\n    # @return [Boolean] true when set else false\n    def has_been_set?\n      @value != NO_VALUE\n    end\n  end\nend\n"
  },
  {
    "path": "lib/functional/memo.rb",
    "content": "require 'functional/synchronization'\n\nmodule Functional\n\n  # Memoization is a technique for optimizing functions that are time-consuming\n  # and/or involve expensive calculations. Every time a memoized function is\n  # called the result is caches with reference to the given parameters.\n  # Subsequent calls to the function that use the same parameters will return\n  # the cached result. As a result the response time for frequently called\n  # functions is vastly increased (after the first call with any given set of)\n  # arguments, at the cost of increased memory usage (the cache).\n  #\n  # {include:file:doc/memo.md}\n  #\n  # @note Memoized method calls are thread safe and can safely be used in\n  #   concurrent systems. Declaring memoization on a function is *not* thread\n  #   safe and should only be done during application initialization.\n  module Memo\n\n    # @!visibility private\n    def self.extended(base)\n      base.extend(ClassMethods)\n      base.send(:__method_memos__=, {})\n      super(base)\n    end\n\n    # @!visibility private\n    def self.included(base)\n      base.extend(ClassMethods)\n      base.send(:__method_memos__=, {})\n      super(base)\n    end\n\n    # @!visibility private\n    module ClassMethods\n\n      # @!visibility private\n      class Memoizer < Synchronization::Object\n        attr_reader :function, :cache, :max_cache\n        def initialize(function, max_cache)\n          super\n          synchronize do\n            @function = function\n            @max_cache = max_cache\n            @cache = {}\n          end\n        end\n        def max_cache?\n          max_cache > 0 && cache.size >= max_cache\n        end\n        public :synchronize\n      end\n      private_constant :Memoizer\n\n      # @!visibility private\n      attr_accessor :__method_memos__\n\n      # Returns a memoized version of a referentially transparent function. The\n      # memoized version of the function keeps a cache of the mapping from\n      # arguments to results and, when calls with the same arguments are\n      # repeated often, has higher performance at the expense of higher memory\n      # use.\n      #\n      # @param [Symbol] func the class/module function to memoize\n      # @param [Hash] opts the options controlling memoization\n      # @option opts [Fixnum] :at_most the maximum number of memos to store in\n      #   the cache; a value of zero (the default) or `nil` indicates no limit\n      #\n      # @raise [ArgumentError] when the method has already been memoized\n      # @raise [ArgumentError] when :at_most option is a negative number\n      def memoize(func, opts = {})\n        func = func.to_sym\n        max_cache = opts[:at_most].to_i\n        raise ArgumentError.new(\"method :#{func} has already been memoized\") if __method_memos__.has_key?(func)\n        raise ArgumentError.new(':max_cache must be > 0') if max_cache < 0\n        __method_memos__[func] = Memoizer.new(method(func), max_cache.to_i)\n        __define_memo_proxy__(func)\n        nil\n      end\n\n      # @!visibility private\n      def __define_memo_proxy__(func)\n        self.class_eval <<-RUBY\n          def self.#{func}(*args, &block)\n            self.__proxy_memoized_method__(:#{func}, *args, &block)\n          end\n        RUBY\n      end\n\n      # @!visibility private\n      def __proxy_memoized_method__(func, *args, &block)\n        memo = self.__method_memos__[func]\n        memo.synchronize do\n          if block_given?\n            memo.function.call(*args, &block)\n          elsif memo.cache.has_key?(args)\n            memo.cache[args]\n          else\n            result = memo.function.call(*args)\n            memo.cache[args] = result unless memo.max_cache?\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/functional/method_signature.rb",
    "content": "module Functional\n\n  module PatternMatching\n\n    # @!visibility private\n    #\n    # Helper functions used when pattern matching runtime arguments against\n    # a method defined with the `defn` function of Functional::PatternMatching.\n    module MethodSignature\n      extend self\n\n      # Do the given arguments match the given function pattern?\n      #\n      # @return [Boolean] true when there is a match else false\n      def match?(pattern, args)\n        return false unless valid_pattern?(args, pattern)\n\n        pattern.length.times.all? do |index|\n          param = pattern[index]\n          arg = args[index]\n\n          all_param_and_last_arg?(pattern, param, index) ||\n            arg_is_type_of_param?(param, arg) ||\n            hash_param_with_matching_arg?(param, arg) ||\n            param_matches_arg?(param, arg)\n        end\n      end\n\n      # Is the given pattern a valid pattern with respect to the given\n      # runtime arguments?\n      #\n      # @return [Boolean] true when the pattern is valid else false\n      def valid_pattern?(args, pattern)\n        (pattern.last == PatternMatching::ALL && args.length >= pattern.length) \\\n          || (args.length == pattern.length)\n      end\n\n      # Is this the last parameter and is it `ALL`?\n      #\n      # @return [Boolean] true when matching else false\n      def all_param_and_last_arg?(pattern, param, index)\n        param == PatternMatching::ALL && index+1 == pattern.length\n      end\n\n      # Is the parameter a class and is the provided argument an instance\n      # of that class?\n      #\n      # @return [Boolean] true when matching else false\n      def arg_is_type_of_param?(param, arg)\n        param.is_a?(Class) && arg.is_a?(param)\n      end\n\n      # Is the given parameter a Hash and does it match the given\n      # runtime argument?\n      #\n      # @return [Boolean] true when matching else false\n      def hash_param_with_matching_arg?(param, arg)\n        param.is_a?(Hash) && arg.is_a?(Hash) && ! param.empty? && param.all? do |key, value|\n          arg.has_key?(key) && (value == PatternMatching::UNBOUND || arg[key] == value)\n        end\n      end\n\n      # Does the given parameter exactly match the given runtime\n      # argument or is the parameter `UNBOUND`?\n      #\n      # @return [Boolean] true when matching else false\n      def param_matches_arg?(param, arg)\n        param == PatternMatching::UNBOUND || param == arg\n      end\n    end\n    private_constant :MethodSignature\n  end\nend\n"
  },
  {
    "path": "lib/functional/option.rb",
    "content": "require 'functional/abstract_struct'\nrequire 'functional/either'\nrequire 'functional/protocol'\nrequire 'functional/synchronization'\n\nFunctional::SpecifyProtocol(:Option) do\n  instance_method :some?, 0\n  instance_method :none?, 0\n  instance_method :some, 0\nend\n\nmodule Functional\n\n  # An optional value that may be none (no value) or some (a value).\n  # This type is a replacement for the use of nil with better type checks. \n  # It is an immutable data structure that extends `AbstractStruct`.\n  #\n  # @see http://functionaljava.googlecode.com/svn/artifacts/3.0/javadoc/index.html Functional Java\n  #\n  # @!macro thread_safe_immutable_object\n  class Option < Synchronization::Object\n    include AbstractStruct\n\n    # @!visibility private \n    NO_OPTION = Object.new.freeze\n\n    self.datatype = :option\n    self.fields = [:some].freeze\n\n    private_class_method :new\n\n    # The reason for the absence of a value when none,\n    # defaults to nil\n    attr_reader :reason\n\n    class << self\n\n      # Construct an `Option` with no value.\n      #\n      # @return [Option] the new option\n      def none(reason = nil)\n        new(nil, true, reason).freeze\n      end\n\n      # Construct an `Option` with the given value.\n      #\n      # @param [Object] value the value of the option\n      # @return [Option] the new option\n      def some(value)\n        new(value, false).freeze\n      end\n    end\n\n    # Does the option have a value?\n    #\n    # @return [Boolean] true if some else false\n    def some?\n      ! none?\n    end\n    alias_method :value?, :some?\n    alias_method :fulfilled?, :some?\n\n    # Is the option absent a value?\n    #\n    # @return [Boolean] true if none else false\n    def none?\n      @none\n    end\n    alias_method :reason?, :none?\n    alias_method :rejected?, :none?\n\n    # The value of this option.\n    #\n    # @return [Object] the value when some else nil\n    def some\n      to_h[:some]\n    end\n    alias_method :value, :some\n\n    # Returns the length of this optional value;\n    # 1 if there is a value, 0 otherwise. \n    #\n    # @return [Fixnum] The length of this optional value;\n    #   1 if there is a value, 0 otherwise.\n    def length\n      none? ? 0 : 1\n    end\n    alias_method :size, :length\n\n    # Perform a logical `and` operation against this option and the\n    # provided option or block. Returns true if this option is some and:\n    #\n    # * other is an `Option` with some value\n    # * other is a truthy value (not nil or false)\n    # * the result of the block is a truthy value\n    #\n    # If a block is given the value of the current option is passed to the\n    # block and the result of block processing will be evaluated for its\n    # truthiness. An exception will be raised if an other value and a\n    # block are both provided.\n    #\n    # @param [Object] other the value to be evaluated against this option\n    # @yieldparam [Object] value the value of this option when some\n    # @return [Boolean] true when the union succeeds else false\n    # @raise [ArgumentError] when given both other and a block\n    def and(other = NO_OPTION)\n      raise ArgumentError.new('cannot give both an option and a block') if other != NO_OPTION && block_given?\n      return false if none?\n\n      if block_given?\n        !! yield(some)\n      elsif Protocol::Satisfy? other, :Option\n        other.some?\n      else\n        !! other\n      end\n    end\n\n    # Perform a logical `or` operation against this option and the\n    # provided option or block. Returns true if this option is some.\n    # If this option is none it returns true if:\n    #\n    # * other is an `Option` with some value\n    # * other is a truthy value (not nil or false)\n    # * the result of the block is a truthy value\n    #\n    # If a block is given the value of the result of block processing\n    # will be evaluated for its truthiness. An exception will be raised\n    # if an other value and a block are both provided.\n    #\n    # @param [Object] other the value to be evaluated against this option\n    # @return [Boolean] true when the intersection succeeds else false\n    # @raise [ArgumentError] when given both other and a block\n    def or(other = NO_OPTION)\n      raise ArgumentError.new('cannot give both an option and a block') if other != NO_OPTION && block_given?\n      return true if some?\n\n      if block_given?\n        !! yield\n      elsif Protocol::Satisfy? other, :Option\n        other.some?\n      else\n        !! other\n      end\n    end\n\n    # Returns the value of this option when some else returns the\n    # value of the other option or block. When the other is also an\n    # option its some value is returned. When the other is any other\n    # value it is simply passed through. When a block is provided the\n    # block is processed and the return value of the block is returned.\n    # An exception will be raised if an other value and a block are\n    # both provided.\n    #\n    # @param [Object] other the value to be evaluated when this is none\n    # @return [Object] this value when some else the value of other\n    # @raise [ArgumentError] when given both other and a block\n    def else(other = NO_OPTION)\n      raise ArgumentError.new('cannot give both an option and a block') if other != NO_OPTION && block_given?\n      return some if some?\n\n      if block_given?\n        yield\n      elsif Protocol::Satisfy? other, :Option\n        other.some\n      else\n        other\n      end\n    end\n\n    # If the condition satisfies, return the given A in some, otherwise, none.\n    #\n    # @param [Object] value The some value to use if the condition satisfies.\n    # @param [Boolean] condition The condition to test (when no block given).\n    # @yield The condition to test (when no condition given).\n    #\n    # @return [Option] A constructed option based on the given condition.\n    #\n    # @raise [ArgumentError] When both a condition and a block are given.\n    def self.iff(value, condition = NO_OPTION)\n      raise ArgumentError.new('requires either a condition or a block, not both') if condition != NO_OPTION && block_given?\n      condition = block_given? ? yield : !! condition\n      condition ? some(value) : none\n    end\n\n    # @!macro inspect_method\n    def inspect\n      super.gsub(/ :some/, \" (#{some? ? 'some' : 'none'}) :some\")\n    end\n    alias_method :to_s, :inspect\n\n    private\n\n    # Create a new Option with the given value and disposition.\n    #\n    # @param [Object] value the value of this option\n    # @param [Boolean] none is this option absent a value?\n    # @param [Object] reason the reason for the absense of a value\n    #\n    # @!visibility private \n    def initialize(value, none, reason = nil)\n      super\n      @none = none\n      @reason = none ? reason : nil\n      hsh = none ? {some: nil} : {some: value}\n      set_data_hash(hsh)\n      set_values_array(hsh.values)\n      ensure_ivar_visibility!\n    end\n  end\nend\n"
  },
  {
    "path": "lib/functional/pattern_matching.rb",
    "content": "require 'functional/method_signature'\n\nmodule Functional\n\n  # As much as I love Ruby I've always been a little disappointed that Ruby\n  # doesn't support function overloading. Function overloading tends to reduce\n  # branching and keep function signatures simpler. No sweat, I learned to do\n  # without. Then I started programming in Erlang. My favorite Erlang feature\n  # is, without question, pattern matching. Pattern matching is like function\n  # overloading cranked to 11. So one day I was musing on Twitter that I'd like\n  # to see Erlang-stype pattern matching in Ruby and one of my friends responded\n  # \"Build it!\" So I did. And here it is.\n  #\n  # {include:file:doc/pattern_matching.md}\n  module PatternMatching\n\n    # A parameter that is required but that can take any value.\n    # @!visibility private\n    UNBOUND = Object.new.freeze\n\n    # A match for one or more parameters in the last position of the match.\n    # @!visibility private\n    ALL = Object.new.freeze\n\n    private\n\n    # A guard clause on a pattern match.\n    # @!visibility private\n    GuardClause = Class.new do\n      def initialize(function, clazz, pattern)\n        @function = function\n        @clazz = clazz\n        @pattern = pattern\n      end\n      def when(&block)\n        unless block_given?\n          raise ArgumentError.new(\"block missing for `when` guard on function `#{@function}` of class #{@clazz}\")\n        end\n        @pattern.guard = block\n        self\n      end\n    end\n    private_constant :GuardClause\n\n    # @!visibility private\n    FunctionPattern = Struct.new(:function, :args, :body, :guard)\n    private_constant :FunctionPattern\n\n    # @!visibility private\n    def __unbound_args__(match, args)\n      argv = []\n      match.args.each_with_index do |p, i|\n        if p == ALL && i == match.args.length-1\n          # when got ALL, then push all to the end to the list of args,\n          # so we can get them as usual *args in matched method\n          argv.concat args[(i..args.length)]\n        elsif p.is_a?(Hash) && p.values.include?(UNBOUND)\n          p.each do |key, value|\n            argv << args[i][key] if value == UNBOUND\n          end\n        elsif p.is_a?(Hash) || p == UNBOUND || p.is_a?(Class)\n          argv << args[i]\n        end\n      end\n      argv\n    end\n\n    def __pass_guard__?(matcher, args)\n      matcher.guard.nil? ||\n        self.instance_exec(*__unbound_args__(matcher, args), &matcher.guard)\n    end\n\n    # @!visibility private\n    def __pattern_match__(clazz, function, *args, &block)\n      args = args.first\n      matchers = clazz.__function_pattern_matches__.fetch(function, [])\n      matchers.detect do |matcher|\n        MethodSignature.match?(matcher.args, args) && __pass_guard__?(matcher, args)\n      end\n    end\n\n    # @!visibility private\n    def self.included(base)\n      base.extend(ClassMethods)\n      super(base)\n    end\n\n    # Class methods added to a class that includes {Functional::PatternMatching}\n    # @!visibility private\n    module ClassMethods\n\n      # @!visibility private\n      def _()\n        UNBOUND\n      end\n\n      # @!visibility private\n      def defn(function, *args, &block)\n        unless block_given?\n          raise ArgumentError.new(\"block missing for definition of function `#{function}` on class #{self}\")\n        end\n\n        # Check that number of free variables in pattern match method's arity\n        pat_arity = __pattern_arity__(args)\n        unless pat_arity == block.arity\n          raise ArgumentError.new(\"Pattern and block arity mismatch: \"\\\n                                    \"#{pat_arity}, #{block.arity}\")\n        end\n\n        # add a new pattern for this function\n        pattern = __register_pattern__(function, *args, &block)\n\n        # define the delegator function if it doesn't exist yet\n        unless self.instance_methods(false).include?(function)\n          __define_method_with_matching__(function)\n        end\n\n        # return a guard clause to be added to the pattern\n        GuardClause.new(function, self, pattern)\n      end\n\n      # @!visibility private\n      # define an arity -1 function that dispatches to the appropriate\n      # pattern match variant or raises an exception\n      def __define_method_with_matching__(function)\n        define_method(function) do |*args, &block|\n          begin\n            # get the collection of matched patterns for this function\n            # use owner to ensure we climb the inheritance tree\n            match = __pattern_match__(self.method(function).owner, function, args, block)\n            if match\n              # call the matched function\n              argv = __unbound_args__(match, args)\n              self.instance_exec(*argv, &match.body)\n            elsif defined?(super)\n              # delegate to the superclass\n              super(*args, &block)\n            else\n              raise NoMethodError.new(\"no method `#{function}` matching \"\\\n                \"#{args} found for class #{self.class}\")\n            end\n          end\n        end\n      end\n\n      # @!visibility private\n      def __function_pattern_matches__\n        @__function_pattern_matches__ ||= Hash.new\n      end\n\n      # @!visibility private\n      def __register_pattern__(function, *args, &block)\n        block = Proc.new{} unless block_given?\n        pattern = FunctionPattern.new(function, args, block)\n        patterns = self.__function_pattern_matches__.fetch(function, [])\n        patterns << pattern\n        self.__function_pattern_matches__[function] = patterns\n        pattern\n      end\n\n      # @!visibility private\n      def __pattern_arity__(pat)\n        r = pat.reduce(0) do |acc, v|\n          if v.is_a?(Hash) \n            ub = v.values.count { |e| e == UNBOUND }\n            # if hash have UNBOUND then treat each unbound as separate arg\n            # alse all hash is one arg\n            ub > 0 ? acc + ub : acc + 1\n          elsif v == ALL || v == UNBOUND || v.is_a?(Class)\n            acc + 1\n          else\n            acc\n          end\n        end\n        pat.last == ALL ? -r : r\n      end\n\n    end\n  end\nend\n"
  },
  {
    "path": "lib/functional/protocol.rb",
    "content": "require 'functional/protocol_info'\n\nmodule Functional\n\n  # An exception indicating a problem during protocol processing.\n  ProtocolError = Class.new(StandardError)\n\n  # Specify a new protocol or retrieve the specification of an existing\n  # protocol.\n  #\n  # When called without a block the global protocol registry will be searched\n  # for a protocol with the matching name. If found the corresponding\n  # {Functional::ProtocolInfo} object will be returned. If not found `nil` will\n  # be returned.\n  #\n  # When called with a block, a new protocol with the given name will be\n  # created and the block will be processed to provide the specifiction.\n  # When successful the new {Functional::ProtocolInfo} object will be returned.\n  # An exception will be raised if a protocol with the same name already\n  # exists.\n  #\n  # @example\n  #   Functional::SpecifyProtocol(:Queue) do\n  #     instance_method :push, 1\n  #     instance_method :pop, 0\n  #     instance_method :length, 0\n  #   end\n  #\n  # @param [Symbol] name The global name of the new protocol\n  # @yield The protocol definition\n  # @return [Functional::ProtocolInfo] the newly created or already existing\n  #   protocol specification\n  #\n  # @raise [Functional::ProtocolError] when attempting to specify a protocol\n  #   that has already been specified.\n  #\n  # @see Functional::Protocol\n  def SpecifyProtocol(name, &block)\n    name = name.to_sym\n    protocol_info = Protocol.class_variable_get(:@@info)[name]\n\n    return protocol_info unless block_given?\n\n    if block_given? && protocol_info\n      raise ProtocolError.new(\":#{name} has already been defined\")\n    end\n\n    info = ProtocolInfo.new(name, &block)\n    Protocol.class_variable_get(:@@info)[name] = info\n  end\n  module_function :SpecifyProtocol\n\n  # Protocols provide a polymorphism and method-dispatch mechanism that eschews\n  # strong typing and embraces the dynamic duck typing of Ruby. Rather than\n  # interrogate a module, class, or object for its type and ancestry, protocols\n  # allow modules, classes, and methods to be interrogated based on their behavior.\n  # It is a logical extension of the `respond_to?` method, but vastly more powerful.\n  #\n  # {include:file:doc/protocol.md}\n  module Protocol\n\n    # The global registry of specified protocols.\n    @@info = {}\n\n    # Does the given module/class/object fully satisfy the given protocol(s)?\n    #\n    # @param [Object] target the method/class/object to interrogate\n    # @param [Symbol] protocols one or more protocols to check against the target\n    # @return [Boolean] true if the target satisfies all given protocols else false\n    #\n    # @raise [ArgumentError] when no protocols given\n    def Satisfy?(target, *protocols)\n      raise ArgumentError.new('no protocols given') if protocols.empty?\n      protocols.all?{|protocol| Protocol.satisfies?(target, protocol.to_sym) }\n    end\n    module_function :Satisfy?\n\n    # Does the given module/class/object fully satisfy the given protocol(s)?\n    # Raises a {Functional::ProtocolError} on failure.\n    #\n    # @param [Object] target the method/class/object to interrogate\n    # @param [Symbol] protocols one or more protocols to check against the target\n    # @return [Symbol] the target\n    #\n    # @raise [Functional::ProtocolError] when one or more protocols are not satisfied\n    # @raise [ArgumentError] when no protocols given\n    def Satisfy!(target, *protocols)\n      Protocol::Satisfy?(target, *protocols) or\n        Protocol.error(target, 'does not', *protocols)\n      target\n    end\n    module_function :Satisfy!\n\n    # Have the given protocols been specified?\n    #\n    # @param [Symbol] protocols the list of protocols to check\n    # @return [Boolean] true if all given protocols have been specified else false\n    #\n    # @raise [ArgumentError] when no protocols are given\n    def Specified?(*protocols)\n      raise ArgumentError.new('no protocols given') if protocols.empty?\n      Protocol.unspecified(*protocols).empty?\n    end\n    module_function :Specified?\n\n    # Have the given protocols been specified?\n    # Raises a {Functional::ProtocolError} on failure.\n    #\n    # @param [Symbol] protocols the list of protocols to check\n    # @return [Boolean] true if all given protocols have been specified\n    #\n    # @raise [Functional::ProtocolError] if one or more of the given protocols have\n    #   not been specified\n    # @raise [ArgumentError] when no protocols are given\n    def Specified!(*protocols)\n      raise ArgumentError.new('no protocols given') if protocols.empty?\n      (unspecified = Protocol.unspecified(*protocols)).empty? or\n        raise ProtocolError.new(\"The following protocols are unspecified: :#{unspecified.join('; :')}.\")\n    end\n    module_function :Specified!\n\n    private\n\n    # Does the target satisfy the given protocol?\n    #\n    # @param [Object] target the module/class/object to check\n    # @param [Symbol] protocol the protocol to check against the target\n    # @return [Boolean] true if the target satisfies the protocol else false\n    def self.satisfies?(target, protocol)\n      info = @@info[protocol]\n      return info && info.satisfies?(target)\n    end\n\n    # Reduces a list of protocols to a list of unspecified protocols.\n    #\n    # @param [Symbol] protocols the list of protocols to check\n    # @return [Array] zero or more unspecified protocols\n    def self.unspecified(*protocols)\n      protocols.drop_while do |protocol|\n        @@info.has_key? protocol.to_sym\n      end\n    end\n\n    # Raise a {Functional::ProtocolError} formatted with the given data.\n    #\n    # @param [Object] target the object that was being interrogated\n    # @param [String] message the message fragment to inject into the error\n    # @param [Symbol] protocols list of protocols that were being checked against the target\n    #\n    # @raise [Functional::ProtocolError] the formatted exception object\n    def self.error(target, message, *protocols)\n      target = target.class unless target.is_a?(Module)\n      raise ProtocolError,\n        \"Value (#{target.class}) '#{target}' #{message} behave as all of: :#{protocols.join('; :')}.\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/functional/protocol_info.rb",
    "content": "require 'functional/synchronization'\n\nmodule Functional\n\n  # An immutable object describing a single protocol and capable of building\n  # itself from a block. Used by {Functional#SpecifyProtocol}.\n  # \n  # @see Functional::Protocol\n  class ProtocolInfo < Synchronization::Object\n\n    # The symbolic name of the protocol\n    attr_reader :name\n\n    # Process a protocol specification block and build a new object.\n    #\n    # @param [Symbol] name the symbolic name of the protocol\n    # @yield self to the given specification block\n    # @return [Functional::ProtocolInfo] the new info object, frozen\n    #\n    # @raise [ArgumentError] when name is nil or an empty string\n    # @raise [ArgumentError] when no block given\n    def initialize(name, &specification)\n      raise ArgumentError.new('no block given') unless block_given?\n      raise ArgumentError.new('no name given') if name.nil? || name.empty?\n      super\n      @name = name.to_sym\n      @info = Info.new({}, {}, [])\n      self.instance_eval(&specification)\n      @info.each_pair{|col, _| col.freeze}\n      @info.freeze\n      ensure_ivar_visibility!\n      self.freeze\n    end\n\n    # The instance methods expected by this protocol.\n    #\n    # @return [Hash] a frozen hash of all instance method names and their\n    #   expected arity for this protocol\n    def instance_methods\n      @info.instance_methods\n    end\n\n    # The class methods expected by this protocol.\n    #\n    # @return [Hash] a frozen hash of all class method names and their\n    #   expected arity for this protocol\n    def class_methods\n      @info.class_methods\n    end\n\n    # The constants expected by this protocol.\n    #\n    # @return [Array] a frozen list of the constants expected by this protocol\n    def constants\n      @info.constants\n    end\n\n    # Does the given module/class/object satisfy this protocol?\n    #\n    # @return [Boolean] true if the target satisfies this protocol else false\n    def satisfies?(target)\n      satisfies_constants?(target) &&\n        satisfies_instance_methods?(target) &&\n        satisfies_class_methods?(target)\n    end\n\n    private\n\n    # Data structure for encapsulating the protocol info data.\n    # @!visibility private\n    Info = Struct.new(:instance_methods, :class_methods, :constants)\n\n    # Does the target satisfy the constants expected by this protocol?\n    #\n    # @param [target] target the module/class/object to interrogate\n    # @return [Boolean] true when satisfied else false\n    def satisfies_constants?(target)\n      clazz = target.is_a?(Module) ? target : target.class\n      @info.constants.all?{|constant| clazz.const_defined?(constant) }\n    end\n\n    # Does the target satisfy the instance methods expected by this protocol?\n    #\n    # @param [target] target the module/class/object to interrogate\n    # @return [Boolean] true when satisfied else false\n    def satisfies_instance_methods?(target)\n      @info.instance_methods.all? do |method, arity|\n        if target.is_a? Module\n          target.method_defined?(method) && check_arity?(target.instance_method(method), arity)\n        else\n          target.respond_to?(method) && check_arity?(target.method(method), arity)\n        end\n      end\n    end\n\n\n    # Does the target satisfy the class methods expected by this protocol?\n    #\n    # @param [target] target the module/class/object to interrogate\n    # @return [Boolean] true when satisfied else false\n    def satisfies_class_methods?(target)\n      clazz = target.is_a?(Module) ? target : target.class\n      @info.class_methods.all? do |method, arity|\n        break false unless clazz.respond_to? method\n        method = clazz.method(method)\n        check_arity?(method, arity)\n      end\n    end\n\n    # Does the given method have the expected arity? Returns true\n    # if the arity of the method is `-1` (variable length argument list\n    # with no required arguments), when expected is `nil` (indicating any\n    # arity is acceptable), or the arity of the method exactly matches the\n    # expected arity.\n    #\n    # @param [Method] method the method object to interrogate\n    # @param [Fixnum] expected the expected arity\n    # @return [Boolean] true when an acceptable match else false\n    #\n    # @see http://www.ruby-doc.org/core-2.1.2/Method.html#method-i-arity Method#arity\n    def check_arity?(method, expected)\n      arity = method.arity\n      expected.nil? || arity == -1 || expected == arity\n    end\n\n    #################################################################\n    # DSL methods\n\n    # Specify an instance method.\n    #\n    # @param [Symbol] name the name of the method\n    # @param [Fixnum] arity the required arity\n    def instance_method(name, arity = nil)\n      arity = arity.to_i unless arity.nil?\n      @info.instance_methods[name.to_sym] = arity\n    end\n\n    # Specify a class method.\n    #\n    # @param [Symbol] name the name of the method\n    # @param [Fixnum] arity the required arity\n    def class_method(name, arity = nil)\n      arity = arity.to_i unless arity.nil?\n      @info.class_methods[name.to_sym] = arity\n    end\n\n    # Specify an instance reader attribute.\n    #\n    # @param [Symbol] name the name of the attribute\n    def attr_reader(name)\n      instance_method(name, 0)\n    end\n\n    # Specify an instance writer attribute.\n    #\n    # @param [Symbol] name the name of the attribute\n    def attr_writer(name)\n      instance_method(\"#{name}=\".to_sym, 1)\n    end\n\n    # Specify an instance accessor attribute.\n    #\n    # @param [Symbol] name the name of the attribute\n    def attr_accessor(name)\n      attr_reader(name)\n      attr_writer(name)\n    end\n\n    # Specify a class reader attribute.\n    #\n    # @param [Symbol] name the name of the attribute\n    def class_attr_reader(name)\n      class_method(name, 0)\n    end\n\n    # Specify a class writer attribute.\n    #\n    # @param [Symbol] name the name of the attribute\n    def class_attr_writer(name)\n      class_method(\"#{name}=\".to_sym, 1)\n    end\n\n    # Specify a class accessor attribute.\n    #\n    # @param [Symbol] name the name of the attribute\n    def class_attr_accessor(name)\n      class_attr_reader(name)\n      class_attr_writer(name)\n    end\n\n    # Specify a constant.\n    #\n    # @param [Symbol] name the name of the constant\n    def constant(name)\n      @info.constants << name.to_sym\n    end\n  end\nend\n"
  },
  {
    "path": "lib/functional/record.rb",
    "content": "require 'functional/abstract_struct'\nrequire 'functional/protocol'\nrequire 'functional/type_check'\n\nmodule Functional\n\n  # An immutable data structure with multiple data fields. A `Record` is a\n  # convenient way to bundle a number of field attributes together,\n  # using accessor methods, without having to write an explicit class.\n  # The `Record` module generates new `AbstractStruct` subclasses that hold a\n  # set of fields with a reader method for each field.\n  #\n  # A `Record` is very similar to a Ruby `Struct` and shares many of its behaviors\n  # and attributes. Unlike a # Ruby `Struct`, a `Record` is immutable: its values\n  # are set at construction and can never be changed. Divergence between the two\n  # classes derive from this core difference.\n  #\n  # {include:file:doc/record.md}\n  #\n  # @see Functional::Union\n  # @see Functional::Protocol\n  # @see Functional::TypeCheck\n  #\n  # @!macro thread_safe_immutable_object\n  module Record\n    extend self\n\n    # Create a new record class with the given fields.\n    #\n    # @return [Functional::AbstractStruct] the new record subclass\n    # @raise [ArgumentError] no fields specified or an invalid type\n    #   specification is given\n    def new(*fields, &block)\n      raise ArgumentError.new('no fields provided') if fields.empty?\n\n      name = nil\n      types = nil\n\n      # check if a name for registration is given\n      if fields.first.is_a?(String)\n        name = fields.first\n        fields = fields[1..fields.length-1]\n      end\n\n      # check for a set of type/protocol specifications\n      if fields.size == 1 && fields.first.respond_to?(:to_h)\n        types = fields.first\n        fields = fields.first.keys\n        check_types!(types)\n      end\n\n      build(name, fields, types, &block)\n    rescue\n      raise ArgumentError.new('invalid specification')\n    end\n\n    private\n\n    # @!visibility private\n    #\n    # A set of restrictions governing the creation of a new record.\n    class Restrictions\n      include Protocol\n      include TypeCheck\n\n      # Create a new restrictions object by processing the given\n      # block. The block should be the DSL for defining a record class.\n      #\n      # @param [Hash] types a hash of fields and the associated type/protocol\n      #   when type/protocol checking is among the restrictions\n      # @param [Proc] block A DSL definition of a new record.\n      # @yield A DSL definition of a new record.\n      def initialize(types = nil, &block)\n        @types = types\n        @required = []\n        @defaults = {}\n        instance_eval(&block) if block_given?\n        @required.freeze\n        @defaults.freeze\n        self.freeze\n      end\n\n      # DSL method for declaring one or more fields to be mandatory.\n      #\n      # @param [Symbol] fields zero or more mandatory fields\n      def mandatory(*fields)\n        @required.concat(fields.collect{|field| field.to_sym})\n      end\n\n      # DSL method for declaring a default value for a field\n      #\n      # @param [Symbol] field the field to be given a default value\n      # @param [Object] value the default value of the field\n      def default(field, value)\n        @defaults[field] = value\n      end\n\n      # Clone a default value if it is cloneable. Else just return\n      # the value.\n      #\n      # @param [Symbol] field the name of the field from which the\n      #   default value is to be cloned.\n      # @return [Object] a clone of the value or the value if uncloneable\n      def clone_default(field)\n        value = @defaults[field]\n        value = value.clone unless uncloneable?(value)\n      rescue TypeError\n        # can't be cloned\n      ensure\n        return value\n      end\n\n      # Validate the record data against this set of restrictions.\n      #\n      # @param [Hash] data the data hash\n      # @raise [ArgumentError] when the data does not match the restrictions\n      def validate!(data)\n        validate_mandatory!(data)\n        validate_types!(data)\n      end\n\n      private\n\n      # Check the given data hash to see if it contains non-nil values for\n      # all mandatory fields.\n      #\n      # @param [Hash] data the data hash\n      # @raise [ArgumentError] if any mandatory fields are missing\n      def validate_mandatory!(data)\n        if data.any?{|k,v| @required.include?(k) && v.nil? }\n          raise ArgumentError.new('mandatory fields must not be nil')\n        end\n      end\n\n      # Validate the record data against a type/protocol specification.\n      #\n      # @param [Hash] data the data hash\n      # @raise [ArgumentError] when the data does not match the specification\n      def validate_types!(data)\n        return if @types.nil?\n        @types.each do |field, type|\n          value = data[field]\n          next if value.nil?\n          if type.is_a? Module\n            raise ArgumentError.new(\"'#{field}' must be of type #{type}\") unless Type?(value, type)\n          else\n            raise ArgumentError.new(\"'#{field}' must stasify the protocol :#{type}\") unless Satisfy?(value, type)\n          end\n        end\n      end\n\n      # Is the given object uncloneable?\n      #\n      # @param [Object] object the object to check\n      # @return [Boolean] true if the object cannot be cloned else false\n      def uncloneable?(object)\n        Type? object, NilClass, TrueClass, FalseClass, Fixnum, Bignum, Float\n      end\n    end\n    private_constant :Restrictions\n\n    # Validate the given type/protocol specification.\n    #\n    # @param [Hash] types the type specification\n    # @raise [ArgumentError] when the specification is not valid\n    def check_types!(types)\n      return if types.nil?\n      unless types.all?{|k,v| v.is_a?(Module) || v.is_a?(Symbol) }\n        raise ArgumentError.new('invalid specification')\n      end\n    end\n\n    # Use the given `AbstractStruct` class and build the methods necessary\n    # to support the given data fields.\n    #\n    # @param [String] name the name under which to register the record when given\n    # @param [Array] fields the list of symbolic names for all data fields\n    # @return [Functional::AbstractStruct] the record class\n    def build(name, fields, types, &block)\n      fields = [name].concat(fields) unless name.nil?\n      record, fields = AbstractStruct.define_class(self, :record, fields)\n      record.class_variable_set(:@@restrictions, Restrictions.new(types, &block))\n      define_initializer(record)\n      fields.each do |field|\n        define_reader(record, field)\n      end\n      record\n    end\n\n    # Define an initializer method on the given record class.\n    #\n    # @param [Functional::AbstractStruct] record the new record class\n    # @return [Functional::AbstractStruct] the record class\n    def define_initializer(record)\n      record.send(:define_method, :initialize) do |data = {}|\n        super()\n        restrictions = record.class_variable_get(:@@restrictions)\n        data = record.fields.reduce({}) do |memo, field|\n          memo[field] = data.fetch(field, restrictions.clone_default(field))\n          memo\n        end\n        restrictions.validate!(data)\n        set_data_hash(data)\n        set_values_array(data.values)\n        ensure_ivar_visibility!\n        self.freeze\n      end\n      record\n    end\n\n    # Define a reader method on the given record class for the given data field.\n    #\n    # @param [Functional::AbstractStruct] record the new record class\n    # @param [Symbol] field symbolic name of the current data field\n    # @return [Functional::AbstractStruct] the record class\n    def define_reader(record, field)\n      record.send(:define_method, field) do\n        to_h[field]\n      end\n      record\n    end\n  end\nend\n"
  },
  {
    "path": "lib/functional/synchronization.rb",
    "content": "module Functional\n\n  # @!visibility private\n  #\n  # Based on work originally done by Petr Chalupa (@pitr-ch) in Concurrent Ruby.\n  # https://github.com/ruby-concurrency/concurrent-ruby/blob/master/lib/concurrent/synchronization/object.rb\n  module Synchronization\n\n    if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'\n\n      require 'jruby'\n\n      # @!visibility private\n      class Object\n\n        # @!visibility private\n        def initialize(*args)\n        end\n\n        protected\n\n        # @!visibility private\n        def synchronize\n          JRuby.reference0(self).synchronized { yield }\n        end\n\n        # @!visibility private\n        def ensure_ivar_visibility!\n          # relying on undocumented behavior of JRuby, ivar access is volatile\n        end\n      end\n\n    elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'\n\n      # @!visibility private\n      class Object\n\n        # @!visibility private\n        def initialize(*args)\n        end\n\n        protected\n\n        # @!visibility private\n        def synchronize(&block)\n          Rubinius.synchronize(self, &block)\n        end\n\n        # @!visibility private\n        def ensure_ivar_visibility!\n          # Rubinius instance variables are not volatile so we need to insert barrier\n          Rubinius.memory_barrier\n        end\n      end\n\n    else\n\n      require 'thread'\n\n      # @!visibility private\n      class Object\n\n        # @!visibility private\n        def initialize(*args)\n          @__lock__      = ::Mutex.new\n          @__condition__ = ::ConditionVariable.new\n        end\n\n        protected\n\n        # @!visibility private\n        def synchronize\n          if @__lock__.owned?\n            yield\n          else\n            @__lock__.synchronize { yield }\n          end\n        end\n\n        # @!visibility private\n        def ensure_ivar_visibility!\n          # relying on undocumented behavior of CRuby, GVL acquire has lock which ensures visibility of ivars\n          # https://github.com/ruby/ruby/blob/ruby_2_2/thread_pthread.c#L204-L211\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/functional/tuple.rb",
    "content": "require 'functional/synchronization'\n\nmodule Functional\n\n  # A tuple is a pure functional data strcture that is similar to an array but is\n  # immutable and of fixed length. Tuples support many of the same operations as\n  # array/list/vector.\n  #\n  # @note The current implementation uses simple Ruby arrays. This is likely to be\n  #   very inefficient for all but the smallest tuples. The more items the tuple\n  #   contains, the less efficient it will become. A future version will use a fast,\n  #   immutable, persistent data structure such as a finger tree or a trie.\n  #\n  # @!macro thread_safe_immutable_object\n  #\n  # @see http://en.wikipedia.org/wiki/Tuple\n  # @see http://msdn.microsoft.com/en-us/library/system.tuple.aspx\n  # @see http://www.tutorialspoint.com/python/python_tuples.htm\n  # @see http://en.cppreference.com/w/cpp/utility/tuple\n  # @see http://docs.oracle.com/javaee/6/api/javax/persistence/Tuple.html\n  # @see http://www.erlang.org/doc/reference_manual/data_types.html\n  # @see http://www.erlang.org/doc/man/erlang.html#make_tuple-2\n  # @see http://en.wikibooks.org/wiki/Haskell/Lists_and_tuples#Tuples\n  class Tuple < Synchronization::Object\n\n    # Create a new tuple with the given data items in the given order.\n    #\n    # @param [Array] data the data items to insert into the new tuple\n    # @raise [ArgumentError] if data is not an array or does not implement `to_a`\n    def initialize(data = [])\n      raise ArgumentError.new('data is not an array') unless data.respond_to?(:to_a)\n      super\n      @data = data.to_a.dup.freeze\n      self.freeze\n      ensure_ivar_visibility!\n    end\n\n    # Retrieve the item at the given index. Indices begin at zero and increment\n    # up, just like Ruby arrays. Negative indicies begin at -1, which represents the\n    # last item in the tuple, and decrement toward the first item. If the\n    # given index is out of range then `nil` is returned.\n    #\n    # @param [Fixnum] index the index of the item to be retrieved\n    # @return [Object] the item at the given index or nil when index is out of bounds\n    def at(index)\n      @data[index]\n    end\n    alias_method :nth, :at\n    alias_method :[], :at\n\n    # Retrieve the item at the given index or return the given default value if the\n    # index is out of bounds. The behavior of indicies follows the rules for the\n    # `at` method.\n    #\n    # @param [Fixnum] index the index of the item to be retrieved\n    # @param [Object] default the value to return when given an out of bounds index\n    # @return [Object] the item at the given index or default when index is out of bounds\n    #\n    # @see Functional::Tuple#at\n    def fetch(index, default)\n      if index >= length || -index > length\n        default\n      else\n        at(index)\n      end\n    end\n\n    # The number of items in the tuple.\n    #\n    # @return [Fixnum] the number of items in the tuple\n    def length\n      @data.length\n    end\n    alias_method :size, :length\n\n    # Returns a new tuple containing elements common to the two tuples, excluding any\n    # duplicates. The order is preserved from the original tuple.\n    #\n    # @!macro [attach] tuple_method_param_other_return_tuple\n    #   @param [Array] other the tuple or array-like object (responds to `to_a`) to operate on\n    #   @return [Functional::Tuple] a new tuple with the appropriate items\n    def intersect(other)\n      Tuple.new(@data & other.to_a)\n    end\n    alias_method :&, :intersect\n\n    # Returns a new tuple by joining self with other, excluding any duplicates and\n    # preserving the order from the original tuple.\n    #\n    # @!macro tuple_method_param_other_return_tuple\n    def union(other)\n      Tuple.new(@data | other.to_a)\n    end\n    alias_method :|, :union\n\n    # Returns a new tuple built by concatenating the two tuples\n    # together to produce a third tuple.\n    #\n    # @!macro tuple_method_param_other_return_tuple\n    def concat(other)\n      Tuple.new(@data + other.to_a)\n    end\n    alias_method :+, :concat\n\n    # Returns a new tuple that is a copy of the original tuple, removing any items that\n    # also appear in other. The order is preserved from the original tuple.\n    #\n    # @!macro tuple_method_param_other_return_tuple\n    def diff(other)\n      Tuple.new(@data - other.to_a)\n    end\n    alias_method :-, :diff\n\n    # Returns a new tuple built by concatenating the given number of copies of self.\n    # Returns an empty tuple when the multiple is zero.\n    #\n    # @param [Fixnum] multiple the number of times to concatenate self\n    # @return [Functional::Tuple] a new tuple with the appropriate items\n    # @raise [ArgumentError] when multiple is a negative number\n    def repeat(multiple)\n      multiple = multiple.to_i\n      raise ArgumentError.new('negative argument') if multiple < 0\n      Tuple.new(@data * multiple)\n    end\n    alias_method :*, :repeat\n\n    # Returns a new tuple by removing duplicate values in self.\n    #\n    # @return [Functional::Tuple] the new tuple with only unique items\n    def uniq\n      Tuple.new(@data.uniq)\n    end\n\n    # Calls the given block once for each element in self, passing that element as a parameter.\n    # An Enumerator is returned if no block is given.\n    #\n    # @yieldparam [Object] item the current item\n    # @return [Enumerable] when no block is given\n    def each\n      return enum_for(:each) unless block_given?\n      @data.each do |item|\n        yield(item)\n      end\n    end\n\n    # Calls the given block once for each element in self, passing that element\n    # and the current index as parameters. An Enumerator is returned if no block is given.\n    #\n    # @yieldparam [Object] item the current item\n    # @yieldparam [Fixnum] index the index of the current item\n    # @return [Enumerable] when no block is given\n    def each_with_index\n      return enum_for(:each_with_index) unless block_given?\n      @data.each_with_index do |item, index|\n        yield(item, index)\n      end\n    end\n\n    # Calls the given block once for each element in self, passing that element\n    # and a tuple with all the remaining items in the tuple. When the last item\n    # is reached ab empty tuple is passed as the second parameter. This is the\n    # classic functional programming `head|tail` list processing idiom.\n    # An Enumerator is returned if no block is given.\n    #\n    # @yieldparam [Object] head the current item for this iteration\n    # @yieldparam [Tuple] tail the remaining items (tail) or an empty tuple when\n    #   processing the last item\n    # @return [Enumerable] when no block is given\n    def sequence\n      return enum_for(:sequence) unless block_given?\n      @data.length.times do |index|\n        last = @data.length - 1\n        if index == last\n          yield(@data[index], Tuple.new)\n        else\n          yield(@data[index], Tuple.new(@data.slice(index+1..last)))\n        end\n      end\n    end\n\n    # Compares this object and other for equality. A tuple is `eql?` to\n    # other when other is a tuple or an array-like object (any object that\n    # responds to `to_a`) and the two objects have identical values in the\n    # same foxed order.\n    #\n    # @param [Object] other the other tuple to compare for equality\n    # @return [Boolean] true when equal else false\n    def eql?(other)\n      @data == other.to_a\n    end\n    alias_method :==, :eql?\n\n    # Returns true if self contains no items.\n    #\n    # @return [Boolean] true when empty else false\n    def empty?\n      @data.empty?\n    end\n\n    # Returns the first element of the tuple or nil when empty.\n    #\n    # @return [Object] the first element or nil\n    def first\n      @data.first\n    end\n    alias_method :head, :first\n\n    # Returns a tuple containing all the items in self after the first\n    # item. Returns an empty tuple when empty or there is only one item.\n    #\n    # @return [Functional::Tuple] the tail of the tuple\n    def rest\n      if @data.length <= 1\n        Tuple.new\n      else\n        Tuple.new(@data.slice(1..@data.length-1))\n      end\n    end\n    alias_method :tail, :rest\n\n    # Create a standard Ruby mutable array containing the tuple items\n    # in the same order.\n    #\n    # @return [Array] the new array created from the tuple\n    def to_a\n      @data.dup\n    end\n    alias_method :to_ary, :to_a\n\n    # Describe the contents of this object in a string.\n    #\n    # @return [String] the string representation of this object\n    #\n    # @!visibility private\n    def inspect\n      \"#<#{self.class}: #{@data.to_s}>\"\n    end\n\n    # Describe the contents of this object in a string that exactly\n    # matches the string that would be created from an identical array.\n    #\n    # @return [String] the string representation of this object\n    #\n    # @!visibility private\n    def to_s\n      @data.to_s\n    end\n  end\nend\n"
  },
  {
    "path": "lib/functional/type_check.rb",
    "content": "module Functional\n\n  # Supplies type-checking helpers whenever included.\n  #\n  # @see http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Actor/TypeCheck.html TypeCheck in Concurrent Ruby\n  module TypeCheck\n\n    # Performs an `is_a?` check of the given value object against the\n    # given list of modules and/or classes.\n    #\n    # @param [Object] value the object to interrogate\n    # @param [Module] types zero or more modules and/or classes to check\n    #   the value against\n    # @return [Boolean] true on success\n    def Type?(value, *types)\n      types.any? { |t| value.is_a? t }\n    end\n    module_function :Type?\n\n    # Performs an `is_a?` check of the given value object against the\n    # given list of modules and/or classes. Raises an exception on failure.\n    #\n    # @param [Object] value the object to interrogate\n    # @param [Module] types zero or more modules and/or classes to check\n    #   the value against\n    # @return [Object] the value object\n    #\n    # @raise [Functional::TypeError] when the check fails\n    def Type!(value, *types)\n      Type?(value, *types) or\n        TypeCheck.error(value, 'is not', types)\n      value\n    end\n    module_function :Type!\n\n    # Is the given value object is an instance of or descendant of\n    # one of the classes/modules in the given list?\n    #\n    # Performs the check using the `===` operator.\n    #\n    # @param [Object] value the object to interrogate\n    # @param [Module] types zero or more modules and/or classes to check\n    #   the value against\n    # @return [Boolean] true on success\n    def Match?(value, *types)\n      types.any? { |t| t === value }\n    end\n    module_function :Match?\n\n    # Is the given value object is an instance of or descendant of\n    # one of the classes/modules in the given list?  Raises an exception\n    # on failure.\n    #\n    # Performs the check using the `===` operator.\n    #\n    # @param [Object] value the object to interrogate\n    # @param [Module] types zero or more modules and/or classes to check\n    #   the value against\n    # @return [Object] the value object\n    #\n    # @raise [Functional::TypeError] when the check fails\n    def Match!(value, *types)\n      Match?(value, *types) or\n        TypeCheck.error(value, 'is not matching', types)\n      value\n    end\n    module_function :Match!\n\n    # Is the given class a subclass or exact match of one or more\n    # of the modules and/or classes in the given list?\n    #\n    # @param [Class] value the class to interrogate\n    # @param [Class] types zero or more classes to check the value against\n    #   the value against\n    # @return [Boolean] true on success\n    def Child?(value, *types)\n      Type?(value, Class) &&\n        types.any? { |t| value <= t }\n    end\n    module_function :Child?\n\n    # Is the given class a subclass or exact match of one or more\n    # of the modules and/or classes in the given list?\n    #\n    # @param [Class] value the class to interrogate\n    # @param [Class] types zero or more classes to check the value against\n    # @return [Class] the value class\n    #\n    # @raise [Functional::TypeError] when the check fails\n    def Child!(value, *types)\n      Child?(value, *types) or\n        TypeCheck.error(value, 'is not child', types)\n      value\n    end\n    module_function :Child!\n\n    private\n\n    # Create a {Functional::TypeError} object from the given data.\n    #\n    # @param [Object] value the class/method that was being interrogated\n    # @param [String] message the message fragment to inject into the error\n    # @param [Object] types list of modules and/or classes that were being\n    #   checked against the value object\n    #\n    # @raise [Functional::TypeError] the formatted exception object\n    def self.error(value, message, types)\n      raise TypeError,\n        \"Value (#{value.class}) '#{value}' #{message} any of: #{types.join('; ')}.\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/functional/union.rb",
    "content": "require 'functional/abstract_struct'\nrequire 'functional/synchronization'\n\nmodule Functional\n\n  # An immutable data structure with multiple fields, only one of which\n  # can be set at any given time. A `Union` is a convenient way to bundle a\n  # number of field attributes together, using accessor methods, without having\n  # to write an explicit class.\n  #\n  # The `Union` module generates new `AbstractStruct` subclasses that hold a set of\n  # fields with one and only one value associated with a single field. For each\n  # field a reader method is created along with a predicate and a factory. The\n  # predicate method indicates whether or not the give field is set. The reader\n  # method returns the value of that field or `nil` when not set. The factory\n  # creates a new union with the appropriate field set with the given value.\n  #\n  # A `Union` is very similar to a Ruby `Struct` and shares many of its behaviors\n  # and attributes. Where a `Struct` can have zero or more values, each of which is\n  # assiciated with a field, a `Union` can have one and only one value. Unlike a\n  # Ruby `Struct`, a `Union` is immutable: its value is set at construction and\n  # it can never be changed. Divergence between the two classes derive from these\n  # two core differences.\n  #\n  # @example Creating a New Class\n  # \n  #   LeftRightCenter = Functional::Union.new(:left, :right, :center) #=> LeftRightCenter\n  #   LeftRightCenter.ancestors #=> [LeftRightCenter, Functional::AbstractStruct... ]\n  #   LeftRightCenter.fields   #=> [:left, :right, :center]\n  #   \n  #   prize = LeftRightCenter.right('One million dollars!') #=> #<union LeftRightCenter... >\n  #   prize.fields #=> [:left, :right, :center]\n  #   prize.values  #=> [nil, \"One million dollars!\", nil]\n  #   \n  #   prize.left?   #=> false\n  #   prize.right?  #=> true\n  #   prize.center? #=> false\n  #   \n  #   prize.left    #=> nil\n  #   prize.right   #=> \"One million dollars!\"\n  #   prize.center  #=> nil\n  #\n  # @example Registering a New Class with Union\n  #\n  #   Functional::Union.new('Suit', :clubs, :diamonds, :hearts, :spades)\n  #    #=> Functional::Union::Suit\n  #\n  #   Functional::Union::Suit.hearts('Queen')\n  #    #=> #<union Functional::Union::Suit :clubs=>nil, :diamonds=>nil, :hearts=>\"Queen\", :spades=>nil>\n  #\n  # @see Functional::Union\n  # @see http://www.ruby-doc.org/core-2.1.2/Struct.html Ruby `Struct` class\n  # @see http://en.wikipedia.org/wiki/Union_type \"Union type\" on Wikipedia\n  #\n  # @!macro thread_safe_immutable_object\n  module Union\n    extend self\n\n    # Create a new union class with the given fields.\n    #\n    # @return [Functional::AbstractStruct] the new union subclass\n    # @raise [ArgumentError] no fields specified\n    def new(*fields)\n      raise ArgumentError.new('no fields provided') if fields.empty?\n      build(fields)\n    end\n\n    private\n\n    # Use the given `AbstractStruct` class and build the methods necessary\n    # to support the given data fields.\n    #\n    # @param [Array] fields the list of symbolic names for all data fields\n    # @return [Functional::AbstractStruct] the union class\n    def build(fields)\n      union, fields = AbstractStruct.define_class(self, :union, fields)\n      union.private_class_method(:new)\n      define_properties(union)\n      define_initializer(union)\n      fields.each do |field|\n        define_reader(union, field)\n        define_predicate(union, field)\n        define_factory(union, field)\n      end\n      union\n    end\n\n    # Define the `field` and `value` attribute readers on the given union class.\n    #\n    # @param [Functional::AbstractStruct] union the new union class\n    # @return [Functional::AbstractStruct] the union class\n    def define_properties(union)\n      union.send(:attr_reader, :field)\n      union.send(:attr_reader, :value)\n      union\n    end\n\n    # Define a predicate method on the given union class for the given data field.\n    #\n    # @param [Functional::AbstractStruct] union the new union class\n    # @param [Symbol] field symbolic name of the current data field\n    # @return [Functional::AbstractStruct] the union class\n    def define_predicate(union, field)\n      union.send(:define_method, \"#{field}?\".to_sym) do\n        @field == field\n      end\n      union\n    end\n\n    # Define a reader method on the given union class for the given data field.\n    #\n    # @param [Functional::AbstractStruct] union the new union class\n    # @param [Symbol] field symbolic name of the current data field\n    # @return [Functional::AbstractStruct] the union class\n    def define_reader(union, field)\n      union.send(:define_method, field) do\n        send(\"#{field}?\".to_sym) ? @value : nil\n      end\n      union\n    end\n\n    # Define an initializer method on the given union class.\n    #\n    # @param [Functional::AbstractStruct] union the new union class\n    # @return [Functional::AbstractStruct] the union class\n    def define_initializer(union)\n      union.send(:define_method, :initialize) do |field, value|\n        super()\n        @field = field\n        @value = value\n        data = fields.reduce({}) do |memo, field|\n          memo[field] = ( field == @field ? @value : nil )\n          memo\n        end\n        set_data_hash(data)\n        set_values_array(data.values)\n        ensure_ivar_visibility!\n        self.freeze\n      end\n      union\n    end\n\n    # Define a factory method on the given union class for the given data field.\n    #\n    # @param [Functional::AbstractStruct] union the new union class\n    # @param [Symbol] field symbolic name of the current data field\n    # @return [Functional::AbstractStruct] the union class\n    def define_factory(union, field)\n      union.class.send(:define_method, field) do |value|\n        new(field, value).freeze\n      end\n      union\n    end\n  end\nend\n"
  },
  {
    "path": "lib/functional/value_struct.rb",
    "content": "require 'functional/synchronization'\n\nmodule Functional\n\n  # A variation on Ruby's `OpenStruct` in which all fields are immutable and\n  # set at instantiation. For compatibility with {Functional::FinalStruct}, \n  # predicate methods exist for all potential fields and these predicates\n  # indicate if the field has been set. Calling a predicate method for a field\n  # that does not exist on the struct will return false.\n  #\n  # Unlike {Functional::Record}, which returns a new class which can be used to\n  # create immutable objects, `ValueStruct` creates simple immutable objects.\n  #\n  # @example Instanciation\n  #   name = Functional::ValueStruct.new(first: 'Douglas', last: 'Adams')\n  #\n  #   name.first   #=> 'Douglas'\n  #   name.last    #=> 'Adams'\n  #   name.first?  #=> true\n  #   name.last?   #=> true\n  #   name.middle? #=> false\n  #\n  # @see Functional::Record\n  # @see Functional::FinalStruct\n  # @see http://www.ruby-doc.org/stdlib-2.1.2/libdoc/ostruct/rdoc/OpenStruct.html\n  #\n  # @!macro thread_safe_immutable_object\n  class ValueStruct < Synchronization::Object\n\n    def initialize(attributes)\n      raise ArgumentError.new('attributes must be given as a hash') unless attributes.respond_to?(:each_pair)\n      super\n      @attribute_hash = {}\n      attributes.each_pair do |field, value|\n        set_attribute(field, value)\n      end\n      @attribute_hash.freeze\n      ensure_ivar_visibility!\n      self.freeze\n    end\n\n    # Get the value of the given field.\n    #\n    # @param [Symbol] field the field to retrieve the value for\n    # @return [Object] the value of the field is set else nil\n    def get(field)\n      @attribute_hash[field.to_sym]\n    end\n    alias_method :[], :get\n\n    # Check the internal hash to unambiguously verify that the given\n    # attribute has been set.\n    #\n    # @param [Symbol] field the field to get the value for\n    # @return [Boolean] true if the field has been set else false\n    def set?(field)\n      @attribute_hash.has_key?(field.to_sym)\n    end\n\n    # Get the current value of the given field if already set else return the given\n    # default value.\n    #\n    # @param [Symbol] field the field to get the value for\n    # @param [Object] default the value to return if the field has not been set\n    # @return [Object] the value of the given field else the given default value\n    def fetch(field, default)\n      @attribute_hash.fetch(field.to_sym, default)\n    end\n\n    # Calls the block once for each attribute, passing the key/value pair as parameters.\n    # If no block is given, an enumerator is returned instead.\n    #\n    # @yieldparam [Symbol] field the struct field for the current iteration\n    # @yieldparam [Object] value the value of the current field\n    #\n    # @return [Enumerable] when no block is given\n    def each_pair\n      return enum_for(:each_pair) unless block_given?\n      @attribute_hash.each do |field, value|\n        yield(field, value)\n      end\n    end\n\n    # Converts the `ValueStruct` to a `Hash` with keys representing each attribute\n    # (as symbols) and their corresponding values.\n    # \n    # @return [Hash] a `Hash` representing this struct\n    def to_h\n      @attribute_hash.dup # dup removes the frozen flag\n    end\n\n    # Compares this object and other for equality. A `ValueStruct` is `eql?` to\n    # other when other is a `ValueStruct` and the two objects have identical\n    # fields and values.\n    #\n    # @param [Object] other the other record to compare for equality\n    # @return [Boolean] true when equal else false\n    def eql?(other)\n      other.is_a?(self.class) && @attribute_hash == other.to_h\n    end\n    alias_method :==, :eql?\n\n    # Describe the contents of this object in a string.\n    #\n    # @return [String] the string representation of this object\n    #\n    # @!visibility private\n    def inspect\n      state = @attribute_hash.to_s.gsub(/^{/, '').gsub(/}$/, '')\n      \"#<#{self.class} #{state}>\"\n    end\n    alias_method :to_s, :inspect\n\n    protected\n\n    # Set the value of the give field to the given value.\n    #\n    # @param [Symbol] field the field to set the value for\n    # @param [Object] value the value to set the field to\n    # @return [Object] the final value of the given field\n    #\n    # @!visibility private\n    def set_attribute(field, value)\n      @attribute_hash[field.to_sym] = value\n    end\n\n    # Check the method name and args for signatures matching potential\n    # final predicate methods. If the signature matches call the appropriate\n    # method\n    #\n    # @param [Symbol] symbol the name of the called function\n    # @param [Array] args zero or more arguments\n    # @return [Object] the result of the proxied method or the `super` call\n    #\n    # @!visibility private\n    def method_missing(symbol, *args)\n      if args.length == 0 && (match = /([^\\?]+)\\?$/.match(symbol))\n        set?(match[1])\n      elsif args.length == 0 && set?(symbol)\n        get(symbol)\n      else\n        super\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/functional/version.rb",
    "content": "module Functional\n\n  # The current gem version.\n  VERSION = '1.3.0'\nend\n"
  },
  {
    "path": "lib/functional.rb",
    "content": "require 'functional/delay'\nrequire 'functional/either'\nrequire 'functional/final_struct'\nrequire 'functional/final_var'\nrequire 'functional/memo'\nrequire 'functional/option'\nrequire 'functional/pattern_matching'\nrequire 'functional/protocol'\nrequire 'functional/protocol_info'\nrequire 'functional/record'\nrequire 'functional/tuple'\nrequire 'functional/type_check'\nrequire 'functional/union'\nrequire 'functional/value_struct'\nrequire 'functional/version'\n\nFunctional::SpecifyProtocol(:Disposition) do\n  instance_method :value, 0\n  instance_method :value?, 0\n  instance_method :reason, 0\n  instance_method :reason?, 0\n  instance_method :fulfilled?, 0\n  instance_method :rejected?, 0\nend\n\n# Erlang, Clojure, and Go inspired functional programming tools to Ruby.\nmodule Functional\n\n  # Infinity\n  Infinity = 1/0.0\n\n  # Not a number\n  NaN = 0/0.0\nend\n"
  },
  {
    "path": "spec/.gitignore",
    "content": ""
  },
  {
    "path": "spec/functional/abstract_struct_shared.rb",
    "content": "shared_examples :abstract_struct do\n\n  specify { Functional::Protocol::Satisfy! struct_class, :Struct }\n\n  let(:other_struct) do\n    Class.new do\n      include Functional::AbstractStruct\n      self.fields = [:foo, :bar, :baz].freeze\n      self.datatype = :other_struct\n    end\n  end\n\n  context 'field collection' do\n\n    it 'contains all possible fields' do\n      expected_fields.each do |field|\n        expect(struct_class.fields).to include(field)\n      end\n    end\n\n    it 'is frozen' do\n      expect(struct_class.fields).to be_frozen\n    end\n\n    it 'does not overwrite fields for other structs' do\n      expect(struct_class.fields).to_not eq other_struct.fields\n    end\n\n    it 'is the same when called on the class and on an object' do\n      expect(struct_class.fields).to eq struct_object.fields\n    end\n  end\n\n  context 'readers' do\n\n    specify '#values returns all values in an array' do\n      expect(struct_object.values).to eq expected_values\n    end\n\n    specify '#values is frozen' do\n      expect(struct_object.values).to be_frozen\n    end\n\n    specify 'exist for each field' do\n      expected_fields.each do |field|\n        expect(struct_object).to respond_to(field)\n        expect(struct_object.method(field).arity).to eq 0\n      end\n    end\n\n    specify 'return the appropriate value all fields' do\n      expected_fields.each_with_index do |field, i|\n        expect(struct_object.send(field)).to eq expected_values[i]\n      end\n    end\n  end\n\n  context 'enumeration' do\n\n    specify '#each_pair with a block iterates over all fields and values' do\n      fields = []\n      values = []\n\n      struct_object.each_pair do |field, value|\n        fields << field\n        values << value\n      end\n\n      expect(fields).to eq struct_object.fields\n      expect(values).to eq struct_object.values\n    end\n\n    specify '#each_pair without a block returns an Enumerable' do\n      expect(struct_object.each_pair).to be_a Enumerable\n    end\n\n    specify '#each with a block iterates over all values' do\n      values = []\n\n      struct_object.each do |value|\n        values << value\n      end\n\n      expect(values).to eq struct_object.values\n    end\n\n    specify '#each without a block returns an Enumerable' do\n      expect(struct_object.each).to be_a Enumerable\n    end\n  end\n\n  context 'reflection' do\n\n    specify 'always creates frozen objects' do\n      expect(struct_object).to be_frozen\n    end\n\n    specify 'asserts equality for two structs of the same class with equal values' do\n      other = struct_object.dup\n\n      expect(struct_object).to eq other\n      expect(struct_object).to eql other\n    end\n\n    specify 'rejects equality for two structs of different classes' do\n      other = Struct.new(*expected_fields).new(*expected_values)\n\n      expect(struct_object).to_not eq other\n      expect(struct_object).to_not eql other\n    end\n\n    specify 'rejects equality for two structs of the same class with different values' do\n      expect(struct_object).to_not eq other_object\n      expect(struct_object).to_not eql other_struct\n    end\n\n    specify '#to_h returns a Hash with all field/value pairs' do\n      hsh = struct_object.to_h\n\n      expect(hsh.keys).to eq struct_object.fields\n      expect(hsh.values).to eq struct_object.values\n    end\n\n    specify '#inspect result is enclosed in brackets' do\n      expect(struct_object.inspect).to match(/^#</)\n      expect(struct_object.inspect).to match(/>$/)\n    end\n\n    specify '#inspect result has lowercase class name as first element' do\n      struct = described_class.to_s.split('::').last.downcase\n      expect(struct_object.inspect).to match(/^#<#{struct} /)\n    end\n\n    specify '#inspect includes all field/value pairs' do\n      struct_object.fields.each_with_index do |field, i|\n        value_regex = \"\\\"?#{struct_object.values[i]}\\\"?\"\n        expect(struct_object.inspect).to match(/:#{field}=>#{value_regex}/)\n      end\n    end\n\n    specify '#inspect is aliased as #to_s' do\n      expect(struct_object.inspect).to eq struct_object.to_s\n    end\n\n    specify '#length returns the number of fields' do\n      expect(struct_object.length).to eq struct_class.fields.length\n      expect(struct_object.length).to eq expected_fields.length\n    end\n\n    specify 'aliases #length as #size' do\n      expect(struct_object.length).to eq struct_object.size\n    end\n  end\nend\n"
  },
  {
    "path": "spec/functional/complex_pattern_matching_spec.rb",
    "content": "require 'ostruct'\n\nclass Bar\n  def greet\n    return 'Hello, World!'\n  end\nend\n\nclass Foo < Bar\n  include Functional::PatternMatching\n\n  attr_accessor :name\n\n  defn(:initialize) { @name = 'baz' }\n  defn(:initialize, _) {|name| @name = name.to_s }\n\n  defn(:greet, _) do |name|\n    \"Hello, #{name}!\"\n  end\n\n  defn(:greet, :male, _) { |name|\n    \"Hello, Mr. #{name}!\"\n  }\n  defn(:greet, :female, _) { |name|\n    \"Hello, Ms. #{name}!\"\n  }\n  defn(:greet, nil, _) { |name|\n    \"Goodbye, #{name}!\"\n  }\n  defn(:greet, _, _) { |_, name|\n    \"Hello, #{name}!\"\n  }\n\n  defn(:hashable, _, {foo: :bar}, _) { |_, opts, _|\n    :foo_bar\n  }\n  defn(:hashable, _, {foo: _, bar: _}, _) { |_, f, b, _|\n    [f, b]\n  }\n  defn(:hashable, _, {foo: _}, _) { |_, f, _|\n    f\n  }\n  defn(:hashable, _, {}, _) { |_,_,_|\n    :empty\n  }\n  defn(:hashable, _, _, _) { |_, _, _|\n    :unbound\n  }\n\n  defn(:options, _) { |opts|\n    opts\n  }\n\n  defn(:recurse) {\n    'w00t!'\n  }\n  defn(:recurse, :match) {\n    recurse()\n  }\n  defn(:recurse, :super) {\n    greet()\n  }\n  defn(:recurse, :instance) {\n    @name\n  }\n  defn(:recurse, _) { |arg|\n    arg\n  }\n\n  defn(:concat, Integer, Integer) { |first, second|\n    first + second\n  }\n  defn(:concat, Integer, String) { |first, second|\n    \"#{first} #{second}\"\n  }\n  defn(:concat, String, String) { |first, second|\n    first + second\n  }\n  defn(:concat, Integer, UNBOUND) { |first, second|\n    first + second.to_i\n  }\n\n  defn(:all, :one, ALL) { |*args|\n    args\n  }\n  defn(:all, :one, Integer, ALL) { |int, *args|\n    [int, args]\n  }\n  defn(:all, 1, _, ALL) { |var, *args|\n    [var, args]\n  }\n  defn(:all, ALL) { |*args|\n    args\n  }\n\n  defn(:old_enough, _){ |_| true }.when{|x| x >= 16 }\n  defn(:old_enough, _){ |_| false }\n\n  defn(:right_age, _) { |_|\n    true\n  }.when{|x| x >= 16 && x <= 104 }\n\n  defn(:right_age, _) { |_|\n    false\n  }\n\n  defn(:wrong_age, _) { |_|\n    true\n  }.when{|x| x < 16 || x > 104 }\n\n  defn(:wrong_age, _) { |_|\n    false\n  }\n  end\n\nclass Baz < Foo\n  def boom_boom_room\n    'zoom zoom zoom'\n  end\n  def who(first, last)\n    [first, last].join(' ')\n  end\nend\n\nclass Fizzbuzz < Baz\n  include Functional::PatternMatching\n  defn(:who, Integer) { |count|\n    (1..count).each.reduce(:+)\n  }\n  defn(:who) { 0 }\nend\n\ndescribe 'complex pattern matching' do\n\n  let(:name) { 'Pattern Matcher' }\n  subject { Foo.new(name) }\n\n  specify { expect(subject.greet).to eq 'Hello, World!' }\n\n  specify { expect(subject.greet('Jerry')).to eq 'Hello, Jerry!' }\n\n  specify { expect(subject.greet(:male, 'Jerry')).to eq 'Hello, Mr. Jerry!' }\n  specify { expect(subject.greet(:female, 'Jeri')).to eq 'Hello, Ms. Jeri!' }\n  specify { expect(subject.greet(:unknown, 'Jerry')).to eq 'Hello, Jerry!' }\n  specify { expect(subject.greet(nil, 'Jerry')).to eq 'Goodbye, Jerry!' }\n\n  # FIXME: This thing is failing because it can't match args that it got\n  # and calling super, which can't handle it also and fail with ArgumentError\n  # because super is usual ruby method, can't say what behavior here is\n  # prefered (keep original ruby, or raise no method error somehow)\n  # specify {\n  #   expect { Foo.new.greet(1,2,3,4,5,6,7) }.to raise_error(NoMethodError)\n  # }\n\n  specify { expect(subject.options(bar: :baz, one: 1, many: 2)).to eq({bar: :baz, one: 1, many: 2}) }\n\n  specify { expect(subject.hashable(:male, {foo: :bar}, :female)).to eq :foo_bar }\n  specify { expect(subject.hashable(:male, {foo: :baz}, :female)).to eq :baz }\n  specify { expect(subject.hashable(:male, {foo: 1, bar: 2}, :female)).to eq [1, 2] }\n  specify { expect(subject.hashable(:male, {foo: 1, baz: 2}, :female)).to eq 1 }\n  specify { expect(subject.hashable(:male, {bar: :baz}, :female)).to eq :unbound }\n  specify { expect(subject.hashable(:male, {}, :female)).to eq :empty }\n\n  specify { expect(subject.recurse).to eq 'w00t!' }\n  specify { expect(subject.recurse(:match)).to eq 'w00t!' }\n  specify { expect(subject.recurse(:super)).to eq 'Hello, World!' }\n  specify { expect(subject.recurse(:instance)).to eq name }\n  specify { expect(subject.recurse(:foo)).to eq :foo }\n\n  specify { expect(subject.concat(1, 1)).to eq 2 }\n  specify { expect(subject.concat(1, 'shoe')).to eq '1 shoe' }\n  specify { expect(subject.concat('shoe', 'fly')).to eq 'shoefly' }\n  specify { expect(subject.concat(1, 2.9)).to eq 3 }\n\n  specify { expect(subject.all(:one, 'a', 'bee', :see)).to eq(['a', 'bee', :see]) }\n  specify { expect(subject.all(:one, 1, 'bee', :see)).to eq([1, 'bee', :see]) }\n  specify { expect(subject.all(1, 'a', 'bee', :see)).to eq(['a', ['bee', :see]]) }\n  specify { expect(subject.all('a', 'bee', :see)).to eq(['a', 'bee', :see]) }\n  specify { expect { subject.all }.to raise_error(NoMethodError) }\n\n  specify { expect(subject.old_enough(20)).to be true }\n  specify { expect(subject.old_enough(10)).to be false }\n\n  specify { expect(subject.right_age(20)).to be true }\n  specify { expect(subject.right_age(10)).to be false }\n  specify { expect(subject.right_age(110)).to be false }\n\n  specify { expect(subject.wrong_age(20)).to be false }\n  specify { expect(subject.wrong_age(10)).to be true }\n  specify { expect(subject.wrong_age(110)).to be true }\n\n  context 'inheritance' do\n\n    specify { expect(Fizzbuzz.new.greet(:male, 'Jerry')).to eq 'Hello, Mr. Jerry!' }\n    specify { expect(Fizzbuzz.new.greet(:female, 'Jeri')).to eq 'Hello, Ms. Jeri!' }\n    specify { expect(Fizzbuzz.new.greet(:unknown, 'Jerry')).to eq 'Hello, Jerry!' }\n    specify { expect(Fizzbuzz.new.greet(nil, 'Jerry')).to eq 'Goodbye, Jerry!' }\n\n    specify { expect(Fizzbuzz.new.who(5)).to eq 15 }\n    specify { expect(Fizzbuzz.new.who()).to eq 0 }\n    # FIXME: same issue with Foo's super here\n    # specify {\n    #   expect {\n    #     Fizzbuzz.new.who('Jerry', 'secret middle name', \"D'Antonio\")\n    #   }.to raise_error(NoMethodError)\n    # }\n\n    specify { expect(Fizzbuzz.new.boom_boom_room).to eq 'zoom zoom zoom' }\n  end\nend\n"
  },
  {
    "path": "spec/functional/delay_spec.rb",
    "content": "module Functional\n\n  describe Delay do\n\n    let!(:fulfilled_value) { 10 }\n    let!(:rejected_reason) { StandardError.new('mojo jojo') }\n\n    let(:pending_subject) do\n      Delay.new{ fulfilled_value }\n    end\n\n    let(:fulfilled_subject) do\n      delay = Delay.new{ fulfilled_value }\n      delay.tap{ delay.value }\n    end\n\n    let(:rejected_subject) do\n      delay = Delay.new{ raise rejected_reason }\n      delay.tap{ delay.value }\n    end\n\n    specify{ Functional::Protocol::Satisfy! Delay, :Disposition }\n\n    context '#initialize' do\n\n      it 'sets the state to :pending' do\n        expect(Delay.new{ nil }.state).to eq :pending\n        expect(Delay.new{ nil }).to be_pending\n      end\n\n      it 'raises an exception when no block given' do\n        expect {\n          Delay.new\n        }.to raise_error(ArgumentError)\n      end\n    end\n\n    context '#state' do\n\n      it 'is :pending when first created' do\n        f = pending_subject\n        expect(f.state).to eq(:pending)\n        expect(f).to be_pending\n      end\n\n      it 'is :fulfilled when the handler completes' do\n        f = fulfilled_subject\n        expect(f.state).to eq(:fulfilled)\n        expect(f).to be_fulfilled\n      end\n\n      it 'is :rejected when the handler raises an exception' do\n        f = rejected_subject\n        expect(f.state).to eq(:rejected)\n        expect(f).to be_rejected\n      end\n    end\n\n    context '#value' do\n\n      let(:task){ proc{ nil } }\n\n      it 'blocks the caller when :pending and timeout is nil' do\n        f = pending_subject\n        expect(f.value).to be_truthy\n        expect(f).to be_fulfilled\n      end\n\n      it 'is nil when :rejected' do\n        expected = rejected_subject.value\n        expect(expected).to be_nil\n      end\n\n      it 'is set to the return value of the block when :fulfilled' do\n        expected = fulfilled_subject.value\n        expect(expected).to eq fulfilled_value\n      end\n\n      it 'does not call the block before #value is called' do\n        expect(task).not_to receive(:call).with(any_args)\n        Delay.new(&task)\n      end\n\n      it 'calls the block when #value is called' do\n        expect(task).to receive(:call).once.with(any_args).and_return(nil)\n        Delay.new(&task).value\n      end\n\n      it 'only calls the block once no matter how often #value is called' do\n        expect(task).to receive(:call).once.with(any_args).and_return(nil)\n        delay = Delay.new(&task)\n        5.times{ delay.value }\n      end\n    end\n\n    context '#reason' do\n\n      it 'is nil when :pending' do\n        expect(pending_subject.reason).to be_nil\n      end\n\n      it 'is nil when :fulfilled' do\n        expect(fulfilled_subject.reason).to be_nil\n      end\n\n      it 'is set to error object of the exception when :rejected' do\n        expect(rejected_subject.reason).to be_a(Exception)\n        expect(rejected_subject.reason.to_s).to match(/#{rejected_reason}/)\n      end\n    end\n\n    context 'predicates' do\n\n      specify '#value? returns true when :fulfilled' do\n        expect(pending_subject).to_not be_value\n        expect(fulfilled_subject).to be_value\n        expect(rejected_subject).to_not be_value\n      end\n\n      specify '#reason? returns true when :rejected' do\n        expect(pending_subject).to_not be_reason\n        expect(fulfilled_subject).to_not be_reason\n        expect(rejected_subject).to be_reason\n      end\n\n      specify '#fulfilled? returns true when :fulfilled' do\n        expect(pending_subject).to_not be_fulfilled\n        expect(fulfilled_subject).to be_fulfilled\n        expect(rejected_subject).to_not be_fulfilled\n      end\n\n      specify '#rejected? returns true when :rejected' do\n        expect(pending_subject).to_not be_rejected\n        expect(fulfilled_subject).to_not be_rejected\n        expect(rejected_subject).to be_rejected\n      end\n\n      specify '#pending? returns true when :pending' do\n        expect(pending_subject).to be_pending\n        expect(fulfilled_subject).to_not be_pending\n        expect(rejected_subject).to_not be_pending\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/functional/either_spec.rb",
    "content": "require_relative 'abstract_struct_shared'\n\nmodule Functional\n\n  describe Either do\n\n    let!(:value){ 42 }\n    let!(:reason){ StandardError.new }\n\n    let!(:expected_fields){ [:left, :right] }\n    let!(:expected_values){ [value, nil] }\n\n    let(:struct_class) { Either }\n    let(:struct_object) { Either.left(value) }\n    let(:other_object) { Either.left(Object.new) }\n\n    let(:left_subject){ Either.left(reason) }\n    let(:right_subject){ Either.right(value) }\n\n    it_should_behave_like :abstract_struct\n\n    specify{ Functional::Protocol::Satisfy! Either, :Either }\n    specify{ Functional::Protocol::Satisfy! Either, :Disposition }\n\n    context 'initialization' do\n\n      it 'cannot be constructed directly' do\n        expect {\n          Either.new\n        }.to raise_error(NameError)\n      end\n\n      it 'sets the left value when constructed by #left' do\n        expect(Either.left(value).left).to eq value\n      end\n\n      it 'sets the right value when constructed by #right' do\n        expect(Either.right(value).right).to eq value\n      end\n\n      it 'freezes the new object' do\n        expect(Either.left(:foo)).to be_frozen\n        expect(Either.right(:foo)).to be_frozen\n      end\n\n      it 'aliases #left to #reason' do\n        expect(Either.reason(value).left).to eq value\n      end\n\n      it 'aliases #right to #value' do\n        expect(Either.value(value).right).to eq value\n      end\n\n      context '#error' do\n\n        it 'sets left to a StandardError with backtrace when no arguments given' do\n          either = Either.error\n          expect(either.left).to be_a StandardError\n          expect(either.left.message).to_not be nil\n          expect(either.left.backtrace).to_not be_empty\n        end\n\n        it 'sets left to a StandardError with the given message' do\n          message = 'custom error message'\n          either = Either.error(message)\n          expect(either.left).to be_a StandardError\n          expect(either.left.message).to eq message\n          expect(either.left.backtrace).to_not be_empty\n        end\n\n        it 'sets left to an object of the given class with the given message' do\n          message = 'custom error message'\n          error_class = ArgumentError\n          either = Either.error(message, error_class)\n          expect(either.left).to be_a error_class\n          expect(either.left.message).to eq message\n          expect(either.left.backtrace).to_not be_empty\n        end\n      end\n    end\n\n    context 'state' do\n\n      specify '#left? returns true when the left value is set' do\n        expect(left_subject).to be_left\n      end\n\n      specify '#left? returns false when the right value is set' do\n        expect(right_subject).to_not be_left\n      end\n\n      specify '#right? returns true when the right value is set' do\n        expect(right_subject).to be_right\n      end\n\n      specify '#right? returns false when the left value is set' do\n        expect(left_subject).to_not be_right\n      end\n\n      specify '#left returns the left value when left is set' do\n        expect(left_subject.left).to eq reason\n      end\n\n      specify '#left returns nil when right is set' do\n        expect(right_subject.left).to be_nil\n      end\n\n      specify '#right returns the right value when right is set' do\n        expect(right_subject.right).to eq value\n      end\n\n      specify '#right returns nil when left is set' do\n        expect(left_subject.right).to be_nil\n      end\n\n      specify 'aliases #left? as #reason?' do\n        expect(left_subject.reason?).to be true\n      end\n\n      specify 'aliases #right? as #value?' do\n        expect(right_subject.value?).to be true\n      end\n\n      specify 'aliases #left as #reason' do\n        expect(left_subject.reason).to eq reason\n        expect(right_subject.reason).to be_nil\n      end\n\n      specify 'aliases #right as #value' do\n        expect(right_subject.value).to eq value\n        expect(left_subject.value).to be_nil\n      end\n    end\n\n    context '#swap' do\n\n      it 'converts a left projection into a right projection' do\n        subject = Either.left(:foo)\n        swapped = subject.swap\n        expect(swapped).to be_right\n        expect(swapped.left).to be_nil\n        expect(swapped.right).to eq :foo\n      end\n\n      it 'converts a right projection into a left projection' do\n        subject = Either.right(:foo)\n        swapped = subject.swap\n        expect(swapped).to be_left\n        expect(swapped.right).to be_nil\n        expect(swapped.left).to eq :foo\n      end\n    end\n\n    context '#either' do\n\n      it 'passes the left value to the left proc when left' do\n        expected = nil\n        subject = Either.left(100)\n        subject.either(\n          ->(left) { expected = left },\n          ->(right) { expected = -1 }\n        )\n        expect(expected).to eq 100\n      end\n\n      it 'returns the value of the left proc when left' do\n        subject = Either.left(100)\n        expect(\n          subject.either(\n            ->(left) { left * 2 },\n            ->(right) { nil }\n          )\n        ).to eq 200\n      end\n\n      it 'passes the right value to the right proc when right' do\n        expected = nil\n        subject = Either.right(100)\n        subject.either(\n          ->(right) { expected = -1 },\n          ->(right) { expected = right }\n        )\n        expect(expected).to eq 100\n      end\n\n      it 'returns the value of the right proc when right' do\n        subject = Either.right(100)\n        expect(\n          subject.either(\n            ->(right) { nil },\n            ->(right) { right * 2 }\n          )\n        ).to eq 200\n      end\n    end\n\n    context '#iff' do\n\n      it 'returns a lefty with the given left value when the boolean is true' do\n        subject = Either.iff(:foo, :bar, true)\n        expect(subject).to be_left\n        expect(subject.left).to eq :foo\n      end\n\n      it 'returns a righty with the given right value when the boolean is false' do\n        subject = Either.iff(:foo, :bar, false)\n        expect(subject).to be_right\n        expect(subject.right).to eq :bar\n      end\n\n      it 'returns a lefty with the given left value when the block is truthy' do\n        subject = Either.iff(:foo, :bar){ :baz }\n        expect(subject).to be_left\n        expect(subject.left).to eq :foo\n      end\n\n      it 'returns a righty with the given right value when the block is false' do\n        subject = Either.iff(:foo, :bar){ false }\n        expect(subject).to be_right\n        expect(subject.right).to eq :bar\n      end\n\n      it 'returns a righty with the given right value when the block is nil' do\n        subject = Either.iff(:foo, :bar){ nil }\n        expect(subject).to be_right\n        expect(subject.right).to eq :bar\n      end\n\n      it 'raises an exception when both a boolean and a block are given' do\n        expect {\n          subject = Either.iff(:foo, :bar, true){ nil }\n        }.to raise_error(ArgumentError)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/functional/final_struct_spec.rb",
    "content": "require 'ostruct'\n\nmodule Functional\n\n  describe FinalStruct do\n\n    context 'instanciation' do\n\n      specify 'with no args defines no fields' do\n        subject = FinalStruct.new\n        expect(subject.to_h).to be_empty\n      end\n\n      specify 'with a hash sets fields using has values' do\n        subject = FinalStruct.new(foo: 1, 'bar' => :two, baz: 'three')\n        expect(subject.foo).to eq 1\n        expect(subject.bar).to eq :two\n        expect(subject.baz).to eq 'three'\n      end\n\n      specify 'with a hash creates true predicates for has keys' do\n        subject = FinalStruct.new(foo: 1, 'bar' => :two, baz: 'three')\n        expect(subject.foo?).to be true\n        expect(subject.bar?).to be true\n        expect(subject.baz?).to be true\n      end\n\n      specify 'can be created from any object that responds to #to_h' do\n        clazz = Class.new do\n          def to_h; {answer: 42, harmless: 'mostly'}; end\n        end\n        struct = clazz.new\n        subject = FinalStruct.new(struct)\n        expect(subject.answer).to eq 42\n        expect(subject.harmless).to eq 'mostly'\n      end\n\n      specify 'raises an exception if given a non-hash argument' do\n        expect {\n          FinalStruct.new(:bogus)\n        }.to raise_error(ArgumentError)\n      end\n    end\n\n    context 'set fields' do\n\n      subject do\n        struct = FinalStruct.new\n        struct.foo = 42\n        struct.bar = \"Don't Panic\"\n        struct\n      end\n\n      specify 'have a reader which returns the value' do\n        expect(subject.foo).to eq 42\n        expect(subject.bar).to eq \"Don't Panic\"\n      end\n\n      specify 'have a predicate which returns true' do\n        expect(subject.foo?).to be true\n        expect(subject.bar?).to be true\n      end\n\n      specify 'raise an exception when written to again' do\n        expect {subject.foo = 0}.to raise_error(Functional::FinalityError)\n        expect {subject.bar = 0}.to raise_error(Functional::FinalityError)\n      end\n    end\n\n    context 'unset fields' do\n\n      subject { FinalStruct.new }\n\n      specify 'have a magic reader that always returns nil' do\n        expect(subject.foo).to be nil\n        expect(subject.bar).to be nil\n        expect(subject.baz).to be nil\n      end\n\n      specify 'have a magic predicate that always returns false' do\n        expect(subject.foo?).to be false\n        expect(subject.bar?).to be false\n        expect(subject.baz?).to be false\n      end\n\n      specify 'have a magic writer that sets the field' do\n        expect(subject.foo = 42).to eq 42\n        expect(subject.bar = :towel).to eq :towel\n        expect(subject.baz = \"Don't Panic\").to eq \"Don't Panic\"\n      end\n    end\n\n    context 'accessors' do\n\n      let!(:field_value_pairs) { {foo: 1, bar: :two, baz: 'three'} }\n\n      subject { FinalStruct.new(field_value_pairs) }\n\n      specify '#get returns the value of a set field' do\n        expect(subject.get(:foo)).to eq 1\n      end\n\n      specify '#get returns nil for an unset field' do\n        expect(subject.get(:bogus)).to be nil\n      end\n\n      specify '#[] is an alias for #get' do\n        expect(subject[:foo]).to eq 1\n        expect(subject[:bogus]).to be nil\n      end\n\n      specify '#set sets the value of an unset field' do\n        subject.set(:harmless, 'mostly')\n        expect(subject.harmless).to eq 'mostly'\n        expect(subject.harmless?).to be true\n      end\n\n      specify '#set raises an exception if the field has already been set' do\n        subject.set(:harmless, 'mostly')\n        expect {\n          subject.set(:harmless, 'extremely')\n        }.to raise_error(Functional::FinalityError)\n      end\n\n      specify '#[]= is an alias for set' do\n        subject[:harmless] = 'mostly'\n        expect(subject.harmless).to eq 'mostly'\n        expect {\n          subject[:harmless] = 'extremely'\n        }.to raise_error(Functional::FinalityError)\n      end\n\n      specify '#set? returns false for an unset field' do\n        expect(subject.set?(:harmless)).to be false\n      end\n\n      specify '#set? returns true for a field that has been set' do\n        subject.set(:harmless, 'mostly')\n        expect(subject.set?(:harmless)).to be true\n      end\n\n      specify '#get_or_set returns the value of a set field' do\n        subject.answer = 42\n        expect(subject.get_or_set(:answer, 100)).to eq 42\n      end\n\n      specify '#get_or_set sets the value of an unset field' do\n        subject.get_or_set(:answer, 42)\n        expect(subject.answer).to eq 42\n        expect(subject.answer?).to be true\n      end\n\n      specify '#get_or_set returns the value of a newly set field' do\n        expect(subject.get_or_set(:answer, 42)).to eq 42\n      end\n\n      specify '#fetch gets the value of a set field' do\n        subject.harmless = 'mostly'\n        expect(subject.fetch(:harmless, 'extremely')).to eq 'mostly'\n      end\n\n      specify '#fetch returns the given value when the field is unset' do\n        expect(subject.fetch(:harmless, 'extremely')).to eq 'extremely'\n      end\n\n      specify '#fetch does not set an unset field' do\n        subject.fetch(:answer, 42)\n        expect(subject.answer).to be_nil\n        expect(subject.answer?).to be false\n      end\n\n      specify '#to_h returns the key/value pairs for all set values' do\n        subject = FinalStruct.new(field_value_pairs)\n        expect(subject.to_h).to eq field_value_pairs\n      end\n\n      specify '#to_h is updated when new fields are added' do\n        subject = FinalStruct.new\n        field_value_pairs.each_pair do |field, value|\n          subject.set(field, value)\n        end\n        expect(subject.to_h).to eq field_value_pairs\n      end\n\n      specify '#each_pair returns an Enumerable when no block given' do\n        subject = FinalStruct.new(field_value_pairs)\n        expect(subject.each_pair).to be_a Enumerable\n      end\n\n      specify '#each_pair enumerates over each field/value pair' do\n        subject = FinalStruct.new(field_value_pairs)\n        result = {}\n\n        subject.each_pair do |field, value|\n          result[field] = value\n        end\n\n        expect(result).to eq field_value_pairs\n      end\n    end\n\n    context 'reflection' do\n\n      specify '#eql? returns true when both define the same fields with the same values' do\n        first = FinalStruct.new(foo: 1, 'bar' => :two, baz: 'three')\n        second = FinalStruct.new(foo: 1, 'bar' => :two, baz: 'three')\n\n        expect(first.eql?(second)).to be true\n        expect(first == second).to be true\n      end\n\n      specify '#eql? returns false when other has different fields defined' do\n        first = FinalStruct.new(foo: 1, 'bar' => :two, baz: 'three')\n        second = FinalStruct.new(foo: 1, 'bar' => :two)\n\n        expect(first.eql?(second)).to be false\n        expect(first == second).to be false\n      end\n\n      specify '#eql? returns false when other has different field values' do\n        first = FinalStruct.new(foo: 1, 'bar' => :two, baz: 'three')\n        second = FinalStruct.new(foo: 1, 'bar' => :two, baz: 3)\n\n        expect(first.eql?(second)).to be false\n        expect(first == second).to be false\n      end\n\n      specify '#eql? returns false when other is not a FinalStruct' do\n        attributes = {answer: 42, harmless: 'mostly'}\n        clazz = Class.new do\n          def to_h; {answer: 42, harmless: 'mostly'}; end\n        end\n        other = clazz.new\n        subject = FinalStruct.new(attributes)\n        expect(subject.eql?(other)).to be false\n        expect(subject == other).to be false\n      end\n\n      specify '#inspect begins with the class name' do\n        subject = FinalStruct.new(foo: 1, 'bar' => :two, baz: 'three')\n        expect(subject.inspect).to match(/^#<#{described_class}\\s+/)\n      end\n\n      specify '#inspect includes all field/value pairs' do\n        field_value_pairs = {foo: 1, 'bar' => :two, baz: 'three'}\n        subject = FinalStruct.new(field_value_pairs)\n\n        field_value_pairs.each do |field, value|\n          expect(subject.inspect).to match(/:#{field}=>\"?:?#{value}\"?/)\n        end\n      end\n\n      specify '#to_s returns the same value as #inspect' do\n        subject = FinalStruct.new(foo: 1, 'bar' => :two, baz: 'three')\n        expect(subject.to_s).to eq subject.inspect\n      end\n\n      specify '#method_missing raises an exception for methods with unrecognized signatures' do\n        expect {\n          subject.foo(1, 2, 3)\n        }.to raise_error(NoMethodError)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/functional/final_var_spec.rb",
    "content": "module Functional\n\n  describe FinalVar do\n\n    context 'instanciation' do\n\n      it 'is unset when no arguments given' do\n        expect(FinalVar.new).to_not be_set\n      end\n\n      it 'is set with the given argument' do\n        expect(FinalVar.new(41)).to be_set\n      end\n    end\n\n    context '#get' do\n\n      subject { FinalVar.new }\n\n      it 'returns nil when unset' do\n        expect(subject.get).to be nil\n      end\n\n      it 'returns the value when set' do\n        expect(FinalVar.new(42).get).to eq 42\n      end\n\n      it 'is aliased as #value' do\n        expect(subject.value).to be nil\n        subject.set(42)\n        expect(subject.value).to eq 42\n      end\n    end\n\n    context '#set' do\n\n      subject { FinalVar.new }\n\n      it 'sets the value when unset' do\n        subject.set(42)\n        expect(subject.get).to eq 42\n      end\n\n      it 'returns the new value when unset' do\n        expect(subject.set(42)).to eq 42\n      end\n\n      it 'raises an exception when already set' do\n        subject.set(42)\n        expect {\n          subject.set(42)\n        }.to raise_error(Functional::FinalityError)\n      end\n\n      it 'is aliased as #value=' do\n        subject.value = 42\n        expect(subject.get).to eq 42\n      end\n    end\n\n    context '#set?' do\n\n      it 'returns false when unset' do\n        expect(FinalVar.new).to_not be_set\n      end\n\n      it 'returns true when set' do\n        expect(FinalVar.new(42)).to be_set\n      end\n\n      it 'is aliased as value?' do\n        expect(FinalVar.new.value?).to be false\n        expect(FinalVar.new(42).value?).to be true\n      end\n    end\n\n    context '#get_or_set' do\n\n      it 'sets the value when unset' do\n        subject = FinalVar.new\n        subject.get_or_set(42)\n        expect(subject.get).to eq 42\n      end\n\n      it 'returns the new value when previously unset' do\n        subject = FinalVar.new\n        expect(subject.get_or_set(42)).to eq 42\n      end\n\n      it 'returns the current value when already set' do\n        subject = FinalVar.new(100)\n        expect(subject.get_or_set(42)).to eq 100\n      end\n    end\n\n    context '#fetch' do\n\n      it 'returns the given default value when unset' do\n        subject = FinalVar.new\n        expect(subject.fetch(42)).to eq 42\n      end\n\n      it 'does not change the current value when unset' do\n        subject = FinalVar.new\n        subject.fetch(42)\n        expect(subject.get).to be nil\n      end\n\n      it 'returns the current value when already set' do\n        subject = FinalVar.new(100)\n        expect(subject.get_or_set(42)).to eq 100\n      end\n    end\n\n    context 'reflection' do\n\n      specify '#eql? returns false when unset' do\n        expect(FinalVar.new.eql?(nil)).to be false\n        expect(FinalVar.new.eql?(42)).to be false\n        expect(FinalVar.new.eql?(FinalVar.new.value)).to be false\n      end\n\n      specify '#eql? returns false when set and the value does not match other' do\n        subject = FinalVar.new(42)\n        expect(subject.eql?(100)).to be false\n      end\n\n      specify '#eql? returns true when set and the value matches other' do\n        subject = FinalVar.new(42)\n        expect(subject.eql?(42)).to be true\n      end\n\n      specify '#eql? returns true when set and other is a FinalVar with the same value' do\n        subject = FinalVar.new(42)\n        other = FinalVar.new(42)\n        expect(subject.eql?(other)).to be true\n      end\n\n      specify 'aliases #== as #eql?' do\n        expect(FinalVar.new == nil).to be false\n        expect(FinalVar.new == 42).to be false\n        expect(FinalVar.new == FinalVar.new).to be false\n        expect(FinalVar.new(42) == 42).to be true\n        expect(FinalVar.new(42) == FinalVar.new(42)).to be true\n      end\n\n      specify '#inspect includes the word \"value\" and the value when set' do\n        subject = FinalVar.new(42)\n        expect(subject.inspect).to match(/value\\s?=\\s?42\\s*>$/)\n      end\n\n      specify '#inspect include the word \"unset\" when unset' do\n        subject = FinalVar.new\n        expect(subject.inspect).to match(/unset\\s*>$/i)\n      end\n\n      specify '#to_s returns nil as a string when unset' do\n        expect(FinalVar.new.to_s).to eq nil.to_s\n      end\n\n      specify '#to_s returns the value as a string when set' do\n        expect(FinalVar.new(42).to_s).to eq 42.to_s\n        expect(FinalVar.new('42').to_s).to eq '42'\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/functional/memo_spec.rb",
    "content": "module Functional\n\n  describe Memo do\n\n    def create_new_memo_class\n      Class.new do\n        include Functional::Memo\n\n        class << self\n          attr_accessor :count\n        end\n\n        self.count = 0\n\n        def self.add(a, b)\n          self.count += 1\n          a + b\n        end\n        memoize :add\n\n        def self.increment(n)\n          self.count += 1\n        end\n\n        def self.exception(ex = StandardError)\n          raise ex\n        end\n      end\n    end\n\n    subject{ create_new_memo_class }\n\n    context 'specification' do\n\n      it 'raises an exception when the method is not defined' do\n        expect {\n          subject.memoize(:bogus)\n        }.to raise_error(NameError)\n      end\n\n      it 'raises an exception when the given method has already been memoized' do\n        expect{\n          subject.memoize(:add)\n        }.to raise_error(ArgumentError)\n      end\n\n      it 'allocates a different cache for each class/module' do\n        class_1 = create_new_memo_class\n        class_2 = create_new_memo_class\n\n        10.times do\n          class_1.add(0, 0)\n          class_2.add(0, 0)\n        end\n\n        expect(class_1.count).to eq 1\n        expect(class_2.count).to eq 1\n      end\n\n      it 'works when included in a class' do\n        subject = Class.new do\n          include Functional::Memo\n          class << self\n            attr_accessor :count\n          end\n          self.count = 0\n          def self.foo\n            self.count += 1\n          end\n          memoize :foo\n        end\n\n        10.times{ subject.foo }\n        expect(subject.count).to eq 1\n      end\n\n      it 'works when included in a module' do\n        subject = Module.new do\n          include Functional::Memo\n          class << self\n            attr_accessor :count\n          end\n          self.count = 0\n          def self.foo\n            self.count += 1\n          end\n          memoize :foo\n        end\n\n        10.times{ subject.foo }\n        expect(subject.count).to eq 1\n      end\n\n      it 'works when extended by a module' do\n        subject = Module.new do\n          extend Functional::Memo\n          class << self\n            attr_accessor :count\n          end\n          self.count = 0\n          def self.foo\n            self.count += 1\n          end\n          memoize :foo\n        end\n\n        10.times{ subject.foo }\n        expect(subject.count).to eq 1\n      end\n    end\n\n    context 'caching behavior' do\n\n      it 'calls the real method on first instance of given args' do\n        subject.add(1, 2)\n        expect(subject.count).to eq 1\n      end\n\n      it 'calls the real method on first instance of given args' do\n        subject.add(1, 2)\n        expect(subject.count).to eq 1\n      end\n\n      it 'uses the memo on second instance of given args' do\n        5.times { subject.add(1, 2) }\n        expect(subject.count).to eq 1\n      end\n\n      it 'calls the real method when given a block' do\n        5.times { subject.add(1, 2){ nil } }\n        expect(subject.count).to eq 5\n      end\n\n      it 'raises an exception when arity does not match' do\n        expect {\n          subject.add\n        }.to raise_error(ArgumentError)\n      end\n    end\n\n    context 'maximum cache size' do\n\n      it 'raises an exception when given a non-positive :at_most' do\n        expect {\n          subject.memoize(:increment, at_most: -1)\n        }.to raise_error(ArgumentError)\n      end\n\n      it 'sets no limit when :at_most not given' do\n        subject.memoize(:increment)\n        10000.times{|i| subject.increment(i) }\n        expect(subject.count).to eq 10000\n      end\n\n      it 'calls the real method when the :at_most size is reached' do\n        subject.memoize(:increment, at_most: 5)\n        10000.times{|i| subject.increment(i % 10) }\n        expect(subject.count).to eq 5005\n      end\n    end\n\n    context 'thread safety' do\n\n      let(:memoizer_factory){ Functional::Memo::ClassMethods.const_get(:Memoizer) }\n      let(:memoizer){ memoizer_factory.new(:func, 0) }\n\n      before(:each) do\n        allow(memoizer_factory).to receive(:new).with(any_args).and_return(memoizer)\n      end\n\n      it 'locks a mutex whenever a memoized function is called' do\n        expect(memoizer).to receive(:synchronize).exactly(:once).with(no_args)\n\n        subject.memoize(:increment)\n        subject.increment(0)\n      end\n\n      it 'unlocks the mutex whenever a memoized function is called' do\n        expect(memoizer).to receive(:synchronize).exactly(:once).with(no_args)\n\n        subject.memoize(:increment)\n        subject.increment(0)\n      end\n\n      it 'unlocks the mutex when the method call raises an exception' do\n        expect(memoizer).to receive(:synchronize).exactly(:once).with(no_args)\n\n        subject.memoize(:exception)\n        begin\n          subject.exception\n        rescue\n          # suppress\n        end\n      end\n\n      it 'uses different mutexes for different functions' do\n        expect(memoizer_factory).to receive(:new).with(any_args).exactly(3).times.and_return(memoizer)\n        # once for memoize(:add) in the definition\n        subject.memoize(:increment)\n        subject.memoize(:exception)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/functional/option_spec.rb",
    "content": "require_relative 'abstract_struct_shared'\nrequire 'securerandom'\n\nmodule Functional\n\n  describe Option do\n\n    let!(:value){ 42 }\n\n    let!(:expected_fields){ [:some] }\n    let!(:expected_values){ [value] }\n\n    let(:struct_class) { Option }\n    let(:struct_object) { Option.some(value) }\n    let(:other_object) { Option.some(Object.new) }\n\n    let(:some_subject){ Option.some(value) }\n    let(:none_subject){ Option.none }\n\n    it_should_behave_like :abstract_struct\n\n    specify{ Functional::Protocol::Satisfy! Option, :Option }\n    specify{ Functional::Protocol::Satisfy! Option, :Disposition }\n\n    let(:some_value){ SecureRandom.uuid }\n    let(:other_value){ SecureRandom.uuid }\n\n    context 'initialization' do\n\n      it 'cannot be constructed directly' do\n        expect {\n          Option.new\n        }.to raise_error(NameError)\n      end\n\n      it 'sets the value when constructed by #some' do\n        expect(Option.some(value).some).to eq value\n      end\n\n      it 'sets the value to nil when constructed by #none' do\n        expect(Option.none.some).to be_nil\n      end\n\n      it 'sets the reason to nil when constructed by #none' do\n        expect(Option.none.reason).to be_nil\n      end\n\n      it 'sets the optional reason when constructed by #none' do\n        reason = 'foobar'\n        expect(Option.none(reason).reason).to eq reason\n      end\n\n      it 'freezes the new object' do\n        expect(Option.some(:foo)).to be_frozen\n        expect(Option.none).to be_frozen\n      end\n    end\n\n    context 'state' do\n\n      specify '#some? returns true when the some value is set' do\n        expect(some_subject).to be_some\n      end\n\n      specify '#some? returns false when none' do\n        expect(none_subject).to_not be_some\n      end\n\n      specify '#none? returns true when none' do\n        expect(none_subject).to be_none\n      end\n\n      specify '#none? returns false when the some value is set' do\n        expect(some_subject).to_not be_none\n      end\n\n      specify '#some returns the some value when some is set' do\n        expect(some_subject.some).to eq value\n      end\n\n      specify '#some returns nil when none is set' do\n        expect(none_subject.some).to be_nil\n      end\n\n      it 'aliases #some? as #fulfilled?' do\n        expect(some_subject).to be_fulfilled\n        expect(none_subject).to_not be_fulfilled\n      end\n\n      it 'aliases #some? as #value?' do\n        expect(some_subject).to be_value\n        expect(none_subject).to_not be_value\n      end\n\n      it 'aliases #none? as #rejected?' do\n        expect(some_subject).to_not be_rejected\n        expect(none_subject).to be_rejected\n      end\n\n      it 'aliases #none? as #reason?' do\n        expect(some_subject).to_not be_reason\n        expect(none_subject).to be_reason\n      end\n\n      it 'aliases #some as #value' do\n        expect(some_subject.value).to eq value\n        expect(none_subject.value).to be_nil\n      end\n\n      specify '#reason returns nil when some' do\n        expect(some_subject.reason).to be_nil\n      end\n    end\n\n    context 'length' do\n\n      it 'returns 1 when some' do\n        expect(Option.some(:foo).length).to eq 1\n      end\n\n      it 'returns 0 when none' do\n        expect(Option.none.length).to eq 0\n      end\n\n      it 'as aliased as #size' do\n        expect(Option.some(:foo).size).to eq 1\n        expect(Option.none.size).to eq 0\n      end\n    end\n\n    context '#and' do\n\n      it 'returns false when none' do\n        expect(Option.none.and(true)).to be false\n      end\n\n      it 'returns true when some and other is a some Option' do\n        other = Option.some(42)\n        expect(Option.some(:foo).and(other)).to be true\n      end\n\n      it 'returns false when some and other is a none Option' do\n        other = Option.none\n        expect(Option.some(:foo).and(other)).to be false\n      end\n\n      it 'passes the value to the given block when some' do\n        expected = false\n        other = ->(some){ expected = some }\n        Option.some(42).and(&other)\n        expect(expected).to eq 42\n      end\n\n      it 'returns true when some and the block returns a truthy value' do\n        other = ->(some){ 'truthy' }\n        expect(Option.some(42).and(&other)).to be true\n      end\n\n      it 'returns false when some and the block returns a falsey value' do\n        other = ->(some){ nil }\n        expect(Option.some(42).and(&other)).to be false\n      end\n\n      it 'returns true when some and given a truthy value' do\n        expect(Option.some(42).and('truthy')).to be true\n      end\n\n      it 'returns false when some and given a falsey value' do\n        expect(Option.some(42).and(nil)).to be false\n      end\n\n      it 'raises an exception when given both a value and a block' do\n        expect {\n          Option.some(42).and(:foo){|some| :bar  }\n        }.to raise_error(ArgumentError)\n      end\n    end\n\n    context '#or' do\n\n      it 'returns true when some' do\n        expect(Option.some(42).or(nil)).to be true\n      end\n\n      it 'returns true when none and other is a some Option' do\n        other = Option.some(42)\n        expect(Option.none.or(other)).to be true\n      end\n\n      it 'returns false when none and other is a none Option' do\n        other = Option.none\n        expect(Option.none.or(other)).to be false\n      end\n\n      it 'returns true when none and the block returns a truthy value' do\n        other = ->{ 42 }\n        expect(Option.none.or(&other)).to be true\n      end\n\n      it 'returns false when none and the block returns a falsey value' do\n        other = ->{ false }\n        expect(Option.none.or(&other)).to be false\n      end\n\n      it 'returns true when none and given a truthy value' do\n        expect(Option.none.or('truthy')).to be true\n      end\n\n      it 'returns false when none and given a falsey value' do\n        expect(Option.none.or(nil)).to be false\n      end\n\n      it 'raises an exception when given both a value and a block' do\n        expect {\n          Option.none.and(:foo){ :bar  }\n        }.to raise_error(ArgumentError)\n      end\n    end\n\n    context '#else' do\n\n      it 'returns the value when some' do\n        expect(Option.some(some_value).else(other_value)).to eq some_value\n      end\n\n      it 'returns the given value when none' do\n        expect(Option.none.else(other_value)).to eq other_value\n      end\n\n      it 'returns the other value when none and given a some Option' do\n        other = Option.some(other_value)\n        expect(Option.none.else(other)).to eq other_value\n      end\n\n      it 'returns nil when none and given a none Option' do\n        other = Option.none\n        expect(Option.none.else(other)).to be_nil\n      end\n\n      it 'returns the result of the given block when none' do\n        other = ->{ other_value }\n        expect(Option.none.else(&other)).to eq other_value\n      end\n\n      it 'raises an exception when given both a value and a block' do\n        expect {\n          Option.none.else(:foo){ :bar  }\n        }.to raise_error(ArgumentError)\n      end\n    end\n\n    context '#iff' do\n\n      it 'returns a some option with the given value when the boolean is true' do\n        subject = Option.iff(:foo, true)\n        expect(subject).to be_some\n        expect(subject.some).to eq :foo\n      end\n\n      it 'returns a none option when the boolean is false' do\n        subject = Option.iff(:foo, false)\n        expect(subject).to be_none\n        expect(subject.some).to be_nil\n      end\n\n      it 'returns a some option with the given value when the block is truthy' do\n        subject = Option.iff(:foo){ :baz }\n        expect(subject).to be_some\n        expect(subject.some).to eq :foo\n      end\n\n      it 'returns a none option when the block is false' do\n        subject = Option.iff(:foo){ false }\n        expect(subject).to be_none\n        expect(subject.some).to be_nil\n      end\n\n      it 'returns a none option when the block is nil' do\n        subject = Option.iff(:foo){ nil }\n        expect(subject).to be_none\n        expect(subject.some).to be_nil\n      end\n\n      it 'raises an exception when both a boolean and a block are given' do\n        expect {\n          subject = Option.iff(:foo, true){ nil }\n        }.to raise_error(ArgumentError)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/functional/pattern_matching_spec.rb",
    "content": "require 'ostruct'\n\nmodule Functional\n\n  describe PatternMatching do\n\n    def new_clazz(&block)\n      clazz = Class.new\n      clazz.send(:include, PatternMatching)\n      clazz.instance_eval(&block) if block_given?\n      return clazz\n    end\n\n    subject { new_clazz }\n\n    context '#defn declaration' do\n\n      it 'can be used within a class declaration' do\n        expect {\n          class Clazz\n            include PatternMatching\n            defn(:foo){}\n          end\n        }.not_to raise_error\n      end\n\n      it 'can be used on a class object' do\n        expect {\n          clazz = Class.new\n          clazz.send(:include, PatternMatching)\n          clazz.defn(:foo){}\n        }.not_to raise_error\n      end\n\n      it 'requires a block' do\n        expect {\n          clazz = Class.new\n          clazz.send(:include, PatternMatching)\n          clazz.defn(:foo)\n        }.to raise_error(ArgumentError)\n      end\n    end\n\n    context 'constructor' do\n\n      it 'can pattern match the constructor' do\n\n        unless RUBY_VERSION == '1.9.2'\n          subject.defn(:initialize, PatternMatching::UNBOUND, PatternMatching::UNBOUND, PatternMatching::UNBOUND) { |_,_,_| 'three args' }\n          subject.defn(:initialize, PatternMatching::UNBOUND, PatternMatching::UNBOUND) { |_,_| 'two args' }\n          subject.defn(:initialize, PatternMatching::UNBOUND) { |_| 'one arg' }\n\n          expect { subject.new(1) }.not_to raise_error\n          expect { subject.new(1, 2) }.not_to raise_error\n          expect { subject.new(1, 2, 3) }.not_to raise_error\n          expect { subject.new(1, 2, 3, 4) }.to raise_error\n        end\n      end\n    end\n\n    context 'parameter count' do\n\n      it 'does not match a call with not enough arguments' do\n\n        subject.defn(:foo, true) { 'expected' }\n\n        expect {\n          subject.new.foo()\n        }.to raise_error(NoMethodError)\n      end\n\n      it 'does not match a call with too many arguments' do\n\n        subject.defn(:foo, true) { 'expected' }\n\n        expect {\n          subject.new.foo(true, false)\n        }.to raise_error(NoMethodError)\n      end\n\n    end\n\n    context 'recursion' do\n\n      it 'defers unmatched calls to the superclass' do\n\n        class UnmatchedCallTesterSuperclass\n          def foo(bar)\n            return bar\n          end\n        end\n\n        class UnmatchedCallTesterSubclass < UnmatchedCallTesterSuperclass\n          include PatternMatching\n          defn(:foo) { 'baz' }\n        end\n\n        subject = UnmatchedCallTesterSubclass.new\n        expect(subject.foo(:bar)).to eq :bar\n      end\n\n      it 'can call another match from within a match' do\n\n        subject.defn(:foo, :bar) { foo(:baz) }\n        subject.defn(:foo, :baz) { 'expected' }\n\n        expect(subject.new.foo(:bar)).to eq 'expected'\n      end\n\n      it 'can call a superclass method from within a match' do\n\n        class RecursiveCallTesterSuperclass\n          def foo(bar)\n            return bar\n          end\n        end\n\n        class RecursiveCallTesterSubclass < RecursiveCallTesterSuperclass\n          include PatternMatching\n          defn(:foo, :bar) { foo(:baz) }\n        end\n\n        subject = RecursiveCallTesterSubclass.new\n        expect(subject.foo(:bar)).to eq :baz\n      end\n    end\n\n    context 'datatypes' do\n\n      it 'matches an argument of the class given in the match parameter' do\n\n        subject.defn(:foo, Integer) { |_| 'expected' }\n        expect(subject.new.foo(100)).to eq 'expected'\n\n        expect {\n          subject.new.foo('hello')\n        }.to raise_error(NoMethodError)\n      end\n\n      it 'passes the matched argument to the block' do\n\n        subject.defn(:foo, Integer) { |arg| arg }\n        expect(subject.new.foo(100)).to eq 100\n      end\n    end\n\n    context 'function with no parameters' do\n\n      it 'accepts no parameters' do\n\n        subject.defn(:foo){}\n        obj = subject.new\n\n        expect {\n          obj.foo\n        }.not_to raise_error\n      end\n\n      it 'does not accept any parameters' do\n\n        subject.defn(:foo){}\n        obj = subject.new\n\n        expect {\n          obj.foo(1)\n        }.to raise_error(NoMethodError)\n      end\n\n      it 'returns the correct value' do\n        subject.defn(:foo){ true }\n        expect(subject.new.foo).to be true\n      end\n    end\n\n    context 'function with one parameter' do\n\n      it 'matches a nil parameter' do\n\n        subject.defn(:foo, nil) { 'expected' }\n        expect(subject.new.foo(nil)).to eq 'expected'\n\n        expect {\n          subject.new.foo('no match should be found')\n        }.to raise_error(NoMethodError)\n      end\n\n      it 'matches a boolean parameter' do\n\n        subject.defn(:foo, true) { 'expected' }\n        subject.defn(:foo, false) { 'false case' }\n\n        expect(subject.new.foo(true)).to eq 'expected'\n        expect(subject.new.foo(false)).to eq 'false case'\n\n        expect {\n          subject.new.foo('no match should be found')\n        }.to raise_error(NoMethodError)\n      end\n\n      it 'matches a symbol parameter' do\n\n        subject.defn(:foo, :bar) { 'expected' }\n        expect(subject.new.foo(:bar)).to eq 'expected'\n\n        expect {\n          subject.new.foo(:baz)\n        }.to raise_error(NoMethodError)\n      end\n\n      it 'matches a number parameter' do\n\n        subject.defn(:foo, 10) { 'expected' }\n        expect(subject.new.foo(10)).to eq 'expected'\n\n        expect {\n          subject.new.foo(11.0)\n        }.to raise_error(NoMethodError)\n      end\n\n      it 'matches a string parameter' do\n\n        subject.defn(:foo, 'bar') { 'expected' }\n        expect(subject.new.foo('bar')).to eq 'expected'\n\n        expect {\n          subject.new.foo('baz')\n        }.to raise_error(NoMethodError)\n      end\n\n      it 'matches an array parameter' do\n\n        subject.defn(:foo, [1, 2, 3]) { 'expected' }\n        expect(subject.new.foo([1, 2, 3])).to eq 'expected'\n\n        expect {\n          subject.new.foo([3, 4, 5])\n        }.to raise_error(NoMethodError)\n      end\n\n      it 'matches a hash parameter' do\n\n        subject.defn(:foo, bar: 1, baz: 2) { |_| 'expected' }\n        expect(subject.new.foo(bar: 1, baz: 2)).to eq 'expected'\n\n        expect {\n          subject.new.foo(foo: 0, bar: 1)\n        }.to raise_error(NoMethodError)\n      end\n\n      it 'matches an object parameter' do\n\n        subject.defn(:foo, OpenStruct.new(foo: :bar)) { 'expected' }\n        expect(subject.new.foo(OpenStruct.new(foo: :bar))).to eq 'expected'\n\n        expect {\n          subject.new.foo(OpenStruct.new(bar: :baz))\n        }.to raise_error(NoMethodError)\n      end\n\n      it 'matches an unbound parameter' do\n\n        subject.defn(:foo, PatternMatching::UNBOUND) {|arg| arg }\n        expect(subject.new.foo(:foo)).to eq :foo\n      end\n    end\n\n    context 'function with two parameters' do\n\n      it 'matches two bound arguments' do\n\n        subject.defn(:foo, :male, :female){ 'expected' }\n        expect(subject.new.foo(:male, :female)).to eq 'expected'\n\n        expect {\n          subject.new.foo(1, 2)\n        }.to raise_error(NoMethodError)\n      end\n\n      it 'matches two unbound arguments' do\n\n        subject.defn(:foo, PatternMatching::UNBOUND, PatternMatching::UNBOUND) do |first, second|\n          [first, second]\n        end\n        expect(subject.new.foo(:male, :female)).to eq [:male, :female]\n      end\n\n      it 'matches when the first argument is bound and the second is not' do\n\n        subject.defn(:foo, :male, PatternMatching::UNBOUND) do |second|\n          second\n        end\n        expect(subject.new.foo(:male, :female)).to eq :female\n      end\n\n      it 'matches when the second argument is bound and the first is not' do\n\n        subject.defn(:foo, PatternMatching::UNBOUND, :female) do |first|\n          first\n        end\n        expect(subject.new.foo(:male, :female)).to eq :male\n      end\n    end\n\n    context 'functions with hash arguments' do\n\n      it 'matches an empty argument hash with an empty parameter hash' do\n\n        subject.defn(:foo, {}) { |_| true }\n        expect(subject.new.foo({})).to be true\n\n        expect {\n          subject.new.foo({one: :two})\n        }.to raise_error(NoMethodError)\n      end\n\n      it 'matches when all hash keys and values match' do\n\n        subject.defn(:foo, {bar: :baz}) { |_| true }\n        expect(subject.new.foo(bar: :baz)).to be true\n\n        expect {\n          subject.new.foo({one: :two})\n        }.to raise_error(NoMethodError)\n      end\n\n      it 'matches when every pattern key/value are in the argument' do\n\n        subject.defn(:foo, {bar: :baz}) { |_| true }\n        expect(subject.new.foo(foo: :bar, bar: :baz)).to be true\n      end\n\n      it 'matches when all keys with unbound values in the pattern have an argument' do\n\n        subject.defn(:foo, {bar: PatternMatching::UNBOUND}) { |_| true }\n        expect(subject.new.foo(bar: :baz)).to be true\n      end\n\n      it 'passes unbound values to the block' do\n\n        subject.defn(:foo, {bar: PatternMatching::UNBOUND}) {|arg| arg }\n        expect(subject.new.foo(bar: :baz)).to eq :baz\n      end\n\n      it 'passes the matched hash to the block' do\n\n        subject.defn(:foo, {bar: :baz}) { |opts| opts }\n        expect(subject.new.foo(bar: :baz)).to eq({bar: :baz})\n      end\n\n      it 'does not match a non-hash argument' do\n\n        subject.defn(:foo, {}) { |_| true }\n\n        expect {\n          subject.new.foo(:bar)\n        }.to raise_error(NoMethodError)\n      end\n\n      it 'supports idiomatic has-as-last-argument syntax' do\n\n        subject.defn(:foo, PatternMatching::UNBOUND) { |opts| opts }\n        expect(subject.new.foo(bar: :baz, one: 1, many: 2)).to eq({bar: :baz, one: 1, many: 2})\n      end\n    end\n\n    context 'varaible-length argument lists' do\n\n      it 'supports ALL as the last parameter' do\n\n        subject.defn(:foo, 1, 2, PatternMatching::ALL) { |*args| args }\n        expect(subject.new.foo(1, 2, 3)).to eq([3])\n        expect(subject.new.foo(1, 2, :foo, :bar)).to eq([:foo, :bar])\n        expect(subject.new.foo(1, 2, :foo, :bar, one: 1, two: 2)).to eq([:foo, :bar, {one: 1, two: 2}])\n      end\n    end\n\n    context 'guard clauses' do\n\n      it 'matches when the guard clause returns true' do\n\n        subject.defn(:old_enough, PatternMatching::UNBOUND){ |_|\n          true\n        }.when{|x| x > 16 }\n\n        expect(subject.new.old_enough(20)).to be true\n      end\n\n      it 'does not match when the guard clause returns false' do\n\n        subject.defn(:old_enough, PatternMatching::UNBOUND){ |_|\n          true\n        }.when{|x| x > 16 }\n\n        expect {\n          subject.new.old_enough(10)\n        }.to raise_error(NoMethodError)\n      end\n\n      it 'continues pattern matching when the guard clause returns false' do\n\n        subject.defn(:old_enough, PatternMatching::UNBOUND){ |_|\n          true\n        }.when{|x| x > 16 }\n\n        subject.defn(:old_enough, PatternMatching::UNBOUND) { |_| false }\n\n        expect(subject.new.old_enough(10)).to be false\n      end\n\n      it 'raises an exception when the guard clause does not have a block' do\n\n        expect {\n          subject.defn(:initialize, PatternMatching::UNBOUND) { 'one arg' }.when\n        }.to raise_error(ArgumentError)\n      end\n    end\n\n    context \"NoMethodError\" do\n      let (:parent) do\n        Class.new { include PatternMatching; def tst; :test end }\n      end\n      let (:child) { Class.new(parent) }\n\n      # let (:child_inst) { child.new }\n\n      it \"throws if pattern don't match and no super\" do\n        child.defn(:no_method) { }\n        expect { child.new.no_method(1) }.to raise_error(NoMethodError)\n      end\n\n      it \"calls super if pattern don't match and there is super\" do\n        child.defn(:tst, PatternMatching::UNBOUND) { |_| }\n        expect(child.new.tst).to eq(:test)\n      end\n\n      it \"throws if it raised inside method body\" do\n        child.defn(:raiser) { raise NoMethodError, \"no_method\" }\n        expect { child.new.raiser }.to raise_error(NoMethodError, \"no_method\")\n      end\n    end\n\n    context \"ArgumentError\" do\n      it \"throws error if block and pattern args missmatch\" do\n        expect do\n          subject.defn(:raise) { |_| }\n        end.to raise_error(ArgumentError)\n\n        expect do\n          subject.defn(:raise, PatternMatching::UNBOUND) { }\n        end.to raise_error(ArgumentError)\n\n        expect do\n          subject.defn(:raise, PatternMatching::ANY) { }\n        end\n\n        expect do\n          subject.defn(:imok,\n            PatternMatching::UNBOUND,\n            { k: _},\n            PatternMatching::ANY) { |_, _, *args| }\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/functional/protocol_info_spec.rb",
    "content": "module Functional\n\n  describe ProtocolInfo do\n\n    let!(:kitchen_sink) do\n      ProtocolInfo.new(:Everything) do\n        instance_method     :instance_method\n        class_method        :class_method\n        attr_accessor       :attr_accessor\n        attr_reader         :attr_reader\n        attr_writer         :attr_writer\n        class_attr_accessor :class_attr_accessor\n        class_attr_reader   :class_attr_reader\n        class_attr_writer   :class_attr_writer\n        constant            :CONSTANT\n      end\n    end\n\n    context '#initialize' do\n\n      it 'raises an exception when no block is given' do\n        expect {\n          ProtocolInfo.new(:Foo)\n        }.to raise_error(ArgumentError)\n      end\n\n      it 'raises an exception when the name is nil' do\n        expect {\n          ProtocolInfo.new(nil){ nil }\n        }.to raise_error(ArgumentError)\n      end\n\n      it 'raises an exception when the name is blank' do\n        expect {\n          ProtocolInfo.new(''){ nil }\n        }.to raise_error(ArgumentError)\n      end\n\n      it 'specifies an instance method with no arity given' do\n        info = ProtocolInfo.new(:Foo) do\n          instance_method :foo\n        end\n\n        expect(info.instance_methods[:foo]).to be_nil\n      end\n\n      it 'specifies an instance method with a given arity' do\n        info = ProtocolInfo.new(:Foo) do\n          instance_method :foo, 2\n        end\n\n        expect(info.instance_methods[:foo]).to eq 2\n      end\n\n      it 'specifies a class method with any arity' do\n        info = ProtocolInfo.new(:Foo) do\n          class_method :foo\n        end\n\n        expect(info.class_methods[:foo]).to be_nil\n      end\n\n      it 'specifies a class method with a given arity' do\n        info = ProtocolInfo.new(:Foo) do\n          class_method :foo, 2\n        end\n\n        expect(info.class_methods[:foo]).to eq 2\n      end\n\n      it 'specifies an instance attribute reader' do\n        info = ProtocolInfo.new(:Foo) do\n          attr_reader :foo\n        end\n\n        expect(info.instance_methods[:foo]).to eq 0\n      end\n\n      it 'specifies an instance attribute writer' do\n        info = ProtocolInfo.new(:Foo) do\n          attr_writer :foo\n        end\n\n        expect(info.instance_methods[:foo=]).to eq 1\n      end\n\n      it 'specifies an instance attribute accessor' do\n        info = ProtocolInfo.new(:Foo) do\n          attr_accessor :foo\n        end\n\n        expect(info.instance_methods[:foo]).to eq 0\n        expect(info.instance_methods[:foo=]).to eq 1\n      end\n\n      it 'specifies a class attribute reader' do\n        info = ProtocolInfo.new(:Foo) do\n          class_attr_reader :foo\n        end\n\n        expect(info.class_methods[:foo]).to eq 0\n      end\n\n      it 'specifies a class attribute writer' do\n        info = ProtocolInfo.new(:Foo) do\n          class_attr_writer :foo\n        end\n\n        expect(info.class_methods[:foo=]).to eq 1\n      end\n\n      it 'specifies a class attribute accessor' do\n        info = ProtocolInfo.new(:Foo) do\n          class_attr_accessor :foo\n        end\n\n        expect(info.class_methods[:foo]).to eq 0\n        expect(info.class_methods[:foo=]).to eq 1\n      end\n\n      it 'specifies a constant' do\n        info = ProtocolInfo.new(:Foo) do\n          constant :FOO\n        end\n\n        expect(info.constants).to include :FOO\n      end\n    end\n\n    context '#satisfies?' do\n\n      it 'validates methods with no arity given' do\n        info = ProtocolInfo.new(:Foo) do\n          instance_method(:bar)\n          class_method(:baz)\n        end\n\n        clazz = Class.new do\n          def bar(a, b, c=1, d=2, *args); nil; end\n          def self.baz(); nil; end\n        end\n\n        expect(info.satisfies?(clazz.new)).to be true\n      end\n\n      it 'validates methods with no parameters' do\n        info = ProtocolInfo.new(:Foo) do\n          instance_method(:bar, 0)\n          class_method(:baz, 0)\n        end\n\n        clazz = Class.new do\n          def bar(); nil; end\n          def self.baz(); nil; end\n        end\n\n        expect(info.satisfies?(clazz.new)).to be true\n      end\n\n      it 'validates methods with a fixed number of parameters' do\n        info = ProtocolInfo.new(:Foo) do\n          instance_method(:bar, 3)\n          class_method(:baz, 3)\n        end\n\n        clazz = Class.new do\n          def bar(a,b,c); nil; end\n          def self.baz(a,b,c); nil; end\n        end\n\n        expect(info.satisfies?(clazz.new)).to be true\n      end\n\n      it 'validates methods with optional parameters' do\n        info = ProtocolInfo.new(:Foo) do\n          instance_method(:bar, -2)\n          class_method(:baz, -2)\n        end\n\n        clazz = Class.new do\n          def bar(a, b=1); nil; end\n          def self.baz(a, b=1, c=2); nil; end\n        end\n\n        expect(info.satisfies?(clazz.new)).to be true\n      end\n\n      ##NOTE: Syntax error on JRuby and Rbx\n      #it 'validates methods with keyword parameters' do\n      #  info = ProtocolInfo.new(:Foo) do\n      #    instance_method(:bar, -2)\n      #    class_method(:baz, -3)\n      #  end\n      #\n      #  clazz = Class.new do\n      #    def bar(a, foo: 'foo', baz: 'baz'); nil; end\n      #    def self.baz(a, b, foo: 'foo', baz: 'baz'); nil; end\n      #  end\n      #\n      #  expect(info.satisfies?(clazz.new)).to be true\n      #end\n\n      it 'validates methods with variable length argument lists' do\n        info = ProtocolInfo.new(:Foo) do\n          instance_method(:bar, -2)\n          class_method(:baz, -3)\n        end\n\n        clazz = Class.new do\n          def bar(a, *args); nil; end\n          def self.baz(a, b, *args); nil; end\n        end\n\n        expect(info.satisfies?(clazz.new)).to be true\n      end\n\n      it 'validates methods with arity -1' do\n        info = ProtocolInfo.new(:Foo) do\n          instance_method(:bar, -1)\n          class_method(:baz, -1)\n        end\n\n        clazz = Class.new do\n          def bar(*args); nil; end\n          def self.baz(*args); nil; end\n        end\n\n        expect(info.satisfies?(clazz.new)).to be true\n      end\n\n      it 'validates instance attribute accessors' do\n        info = ProtocolInfo.new(:Foo) do\n          attr_accessor :foo\n        end\n\n        accessor_clazz = Class.new do\n          attr_accessor :foo\n        end\n\n        manual_clazz = Class.new do\n          def foo() true; end\n          def foo=(value) true; end\n        end\n\n        expect(info.satisfies?(accessor_clazz.new)).to be true\n        expect(info.satisfies?(manual_clazz.new)).to be true\n      end\n\n      it 'validates class attribute accessors' do\n        info = ProtocolInfo.new(:Foo) do\n          class_attr_accessor :foo\n        end\n\n        accessor_clazz = Class.new do\n          class << self\n            attr_accessor :foo\n          end\n        end\n\n        manual_clazz = Class.new do\n          def self.foo() true; end\n          def self.foo=(value) true; end\n        end\n\n        expect(info.satisfies?(accessor_clazz.new)).to be true\n        expect(info.satisfies?(manual_clazz.new)).to be true\n      end\n\n      it 'validates constants' do\n        info = ProtocolInfo.new(:Foo) do\n          constant :FOO\n        end\n\n        clazz = Class.new do\n          FOO = 42\n        end\n\n        expect(info.satisfies?(clazz.new)).to be false\n      end\n\n      it 'always accepts methods when arity not given' do\n        info = ProtocolInfo.new(:Foo) do\n          instance_method(:foo)\n          instance_method(:bar)\n          instance_method(:baz)\n          class_method(:foo)\n          class_method(:bar)\n          class_method(:baz)\n        end\n\n        clazz = Class.new do\n          def foo(); nil; end\n          def bar(a, b, c); nil; end\n          def baz(a, b, *args); nil; end\n          def self.foo(); nil; end\n          def self.bar(a, b, c); nil; end\n          def self.baz(a, b, *args); nil; end\n        end\n\n        expect(info.satisfies?(clazz.new)).to be true\n      end\n\n      it 'always accepts methods with arity -1' do\n        info = ProtocolInfo.new(:Foo) do\n          instance_method(:foo, 0)\n          instance_method(:bar, 2)\n          instance_method(:baz, -2)\n          class_method(:foo, 0)\n          class_method(:bar, -2)\n          class_method(:baz, 2)\n        end\n\n        clazz = Class.new do\n          def foo(*args); nil; end\n          def bar(*args); nil; end\n          def baz(*args); nil; end\n          def self.foo(*args); nil; end\n          def self.bar(*args); nil; end\n          def self.baz(*args); nil; end\n        end\n\n        expect(info.satisfies?(clazz.new)).to be true\n      end\n\n      it 'returns false if one or more instance methods do not match' do\n        info = ProtocolInfo.new(:Foo) do\n          instance_method(:bar, 0)\n        end\n\n        clazz = Class.new do\n          def bar(a, b, *args); nil; end\n        end\n\n        expect(info.satisfies?(clazz.new)).to be false\n      end\n\n      it 'returns false if one or more class methods do not match' do\n        info = ProtocolInfo.new(:Foo) do\n          class_method(:bar, 0)\n        end\n\n        clazz = Class.new do\n          def self.bar(a, b, *args); nil; end\n        end\n\n        expect(info.satisfies?(clazz.new)).to be false\n      end\n\n      it 'returns false if one or more instance attributes does not match' do\n        info = ProtocolInfo.new(:Foo) do\n          attr_accessor :foo\n        end\n\n        reader_clazz = Class.new do\n          def foo() true; end\n          def foo=() false; end\n        end\n\n        writer_clazz = Class.new do\n          def foo(value) false; end\n          def foo=(value) true; end\n        end\n\n        expect(info.satisfies?(reader_clazz.new)).to be false\n        expect(info.satisfies?(writer_clazz.new)).to be false\n      end\n\n      it 'returns false if one or more class attributes does not match' do\n        info = ProtocolInfo.new(:Foo) do\n          class_attr_accessor :foo\n        end\n\n        reader_clazz = Class.new do\n          def self.foo() true; end\n          def self.foo=() false; end\n        end\n\n        writer_clazz = Class.new do\n          def self.foo(value) false; end\n          def self.foo=(value) true; end\n        end\n\n        expect(info.satisfies?(reader_clazz.new)).to be false\n        expect(info.satisfies?(writer_clazz.new)).to be false\n      end\n\n      it 'returns false if one or more constants has not been defined' do\n        info = ProtocolInfo.new(:Foo) do\n          constant :FOO\n        end\n\n        clazz = Class.new do\n          BAR = 42\n        end\n\n        expect(info.satisfies?(clazz.new)).to be false\n      end\n\n      it 'supports all specifiable characteristics on classes' do\n        clazz = Class.new do\n          attr_accessor :attr_accessor\n          attr_reader   :attr_reader\n          attr_writer   :attr_writer\n          def instance_method() 42; end\n\n          class << self\n            attr_accessor :class_attr_accessor\n            attr_reader   :class_attr_reader\n            attr_writer   :class_attr_writer\n            def class_method() 42; end\n          end\n        end\n        clazz.const_set(:CONSTANT, 42)\n\n        expect(\n          kitchen_sink.satisfies?(clazz)\n        ).to be true\n      end\n\n      it 'supports all specifiable characteristics on modules' do\n        mod = Module.new do\n          attr_accessor :attr_accessor\n          attr_reader   :attr_reader\n          attr_writer   :attr_writer\n          def instance_method() 42; end\n\n          class << self\n            attr_accessor :class_attr_accessor\n            attr_reader   :class_attr_reader\n            attr_writer   :class_attr_writer\n            def class_method() 42; end\n          end\n        end\n        mod.const_set(:CONSTANT, 42)\n\n        expect(\n          kitchen_sink.satisfies?(mod)\n        ).to be true\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/functional/protocol_spec.rb",
    "content": "describe 'protocol specification' do\n\n  before(:each) do\n    @protocol_info = Functional::Protocol.class_variable_get(:@@info)\n    Functional::Protocol.class_variable_set(:@@info, {})\n  end\n\n  after(:each) do\n    Functional::Protocol.class_variable_set(:@@info, @protocol_info)\n  end\n\n  context 'SpecifyProtocol method' do\n\n    context 'without a block' do\n\n      it 'returns the specified protocol when defined' do\n        Functional::SpecifyProtocol(:Foo){ nil }\n        expect(Functional::SpecifyProtocol(:Foo)).to_not be_nil\n      end\n\n      it 'returns nil when not defined' do\n        expect(Functional::SpecifyProtocol(:Foo)).to be_nil\n      end\n    end\n\n    context 'with a block' do\n\n      it 'raises an exception if the protocol has already been specified' do\n        Functional::SpecifyProtocol(:Foo){ nil }\n\n        expect {\n          Functional::SpecifyProtocol(:Foo){ nil }\n        }.to raise_error(Functional::ProtocolError)\n      end\n\n      it 'returns the specified protocol once defined' do\n        expect(Functional::SpecifyProtocol(:Foo){ nil }).to be_a Functional::ProtocolInfo\n      end\n    end\n  end\n\n  describe Functional::Protocol do\n\n    context 'Satisfy?' do\n\n      it 'accepts and checks multiple protocols' do\n        Functional::SpecifyProtocol(:foo){ instance_method(:foo) }\n        Functional::SpecifyProtocol(:bar){ instance_method(:foo) }\n        Functional::SpecifyProtocol(:baz){ instance_method(:foo) }\n\n        clazz = Class.new do\n          def foo(); nil; end\n        end\n\n        expect(\n          Functional::Protocol.Satisfy?(clazz.new, :foo, :bar, :baz)\n        ).to be true\n      end\n\n      it 'returns false if one or more protocols have not been defined' do\n        Functional::SpecifyProtocol(:foo){ instance_method(:foo) }\n\n        expect(\n          Functional::Protocol.Satisfy?('object', :foo, :bar)\n        ).to be false\n      end\n\n      it 'raises an exception if no protocols are listed' do\n        expect {\n          Functional::Protocol::Satisfy?('object')\n        }.to raise_error(ArgumentError)\n      end\n\n      it 'returns true on success' do\n        Functional::SpecifyProtocol(:foo){ instance_method(:foo) }\n\n        clazz = Class.new do\n          def foo(); nil; end\n        end\n\n        expect(\n          Functional::Protocol.Satisfy?(clazz.new, :foo)\n        ).to be true\n      end\n\n      it 'returns false on failure' do\n        Functional::SpecifyProtocol(:foo) do\n          instance_method(:foo, 0)\n          class_method(:bar, 0)\n        end\n\n        clazz = Class.new do\n          def foo(); nil; end\n        end\n\n        expect(\n          Functional::Protocol.Satisfy?(clazz.new, :foo)\n        ).to be false\n      end\n\n      it 'validates classes' do\n        Functional::SpecifyProtocol(:foo) do\n          instance_method(:foo)\n          class_method(:bar)\n        end\n\n        clazz = Class.new do\n          def foo(); nil; end\n          def self.bar(); nil; end\n        end\n\n        expect(\n          Functional::Protocol.Satisfy?(clazz, :foo)\n        ).to be true\n      end\n\n      it 'validates modules' do\n        Functional::SpecifyProtocol(:foo) do\n          instance_method(:foo)\n          class_method(:bar)\n        end\n\n        mod = Module.new do\n          def foo(); nil; end\n          def self.bar(); nil; end\n        end\n\n        expect(\n          Functional::Protocol.Satisfy?(mod, :foo)\n        ).to be true\n      end\n    end\n\n    context 'Satisfy!' do\n\n      it 'accepts and checks multiple protocols' do\n        Functional::SpecifyProtocol(:foo){ instance_method(:foo) }\n        Functional::SpecifyProtocol(:bar){ instance_method(:foo) }\n        Functional::SpecifyProtocol(:baz){ instance_method(:foo) }\n\n        clazz = Class.new do\n          def foo(); nil; end\n        end\n\n        target = clazz.new\n        expect(\n          Functional::Protocol.Satisfy!(target, :foo, :bar, :baz)\n        ).to eq target\n      end\n\n      it 'raises an exception if one or more protocols have not been defined' do\n        Functional::SpecifyProtocol(:foo){ instance_method(:foo) }\n\n        expect{\n          Functional::Protocol.Satisfy!('object', :foo, :bar)\n        }.to raise_error(Functional::ProtocolError)\n      end\n\n      it 'raises an exception if no protocols are listed' do\n        expect {\n          Functional::Protocol::Satisfy!('object')\n        }.to raise_error(ArgumentError)\n      end\n\n      it 'returns the target on success' do\n        Functional::SpecifyProtocol(:foo){ instance_method(:foo) }\n\n        clazz = Class.new do\n          def foo(); nil; end\n        end\n\n        target = clazz.new\n        expect(\n          Functional::Protocol.Satisfy!(target, :foo)\n        ).to eq target\n      end\n\n      it 'raises an exception on failure' do\n        Functional::SpecifyProtocol(:foo){ instance_method(:foo) }\n\n        expect{\n          Functional::Protocol.Satisfy!('object', :foo)\n        }.to raise_error(Functional::ProtocolError)\n      end\n\n      it 'validates classes' do\n        Functional::SpecifyProtocol(:foo) do\n          instance_method(:foo)\n          class_method(:bar)\n        end\n\n        clazz = Class.new do\n          def foo(); nil; end\n          def self.bar(); nil; end\n        end\n\n        expect{\n          Functional::Protocol.Satisfy!(clazz, :foo)\n        }.to_not raise_exception\n      end\n\n      it 'validates modules' do\n        Functional::SpecifyProtocol(:foo) do\n          instance_method(:foo)\n          class_method(:bar)\n        end\n\n        mod = Module.new do\n          def foo(); nil; end\n          def self.bar(); nil; end\n        end\n\n        expect{\n          Functional::Protocol.Satisfy!(mod, :foo)\n        }.to_not raise_exception\n      end\n    end\n\n    context 'Specified?' do\n\n      it 'returns true when all protocols have been defined' do\n        Functional::SpecifyProtocol(:foo){ nil }\n        Functional::SpecifyProtocol(:bar){ nil }\n        Functional::SpecifyProtocol(:baz){ nil }\n\n        expect(Functional::Protocol.Specified?(:foo, :bar, :baz)).to be true\n      end\n\n      it 'returns false when one or more of the protocols have not been defined' do\n        Functional::SpecifyProtocol(:foo){ nil }\n        Functional::SpecifyProtocol(:bar){ nil }\n\n        expect(Functional::Protocol.Specified?(:foo, :bar, :baz)).to be false\n      end\n\n      it 'raises an exception when no protocols are given' do\n        expect {\n          Functional::Protocol.Specified?\n        }.to raise_error(ArgumentError)\n      end\n    end\n\n    context 'Specified!' do\n\n      it 'returns true when all protocols have been defined' do\n        Functional::SpecifyProtocol(:foo){ nil }\n        Functional::SpecifyProtocol(:bar){ nil }\n        Functional::SpecifyProtocol(:baz){ nil }\n\n        expect(Functional::Protocol.Specified!(:foo, :bar, :baz)).to be true\n        expect {\n          Functional::Protocol.Specified!(:foo, :bar, :baz)\n        }.to_not raise_error\n      end\n\n      it 'raises an exception when one or more of the protocols have not been defined' do\n        Functional::SpecifyProtocol(:foo){ nil }\n        Functional::SpecifyProtocol(:bar){ nil }\n\n        expect {\n          Functional::Protocol.Specified!(:foo, :bar, :baz)\n        }.to raise_error(Functional::ProtocolError)\n      end\n\n      it 'raises an exception when no protocols are given' do\n        expect {\n          Functional::Protocol.Specified!\n        }.to raise_error(ArgumentError)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/functional/record_spec.rb",
    "content": "require_relative 'abstract_struct_shared'\nrequire 'securerandom'\n\nmodule Functional\n\n  describe Record do\n\n    let!(:expected_fields){ [:a, :b, :c] }\n    let!(:expected_values){ [42, nil, nil] }\n\n    let(:struct_class) { Record.new(*expected_fields) }\n    let(:struct_object) { struct_class.new(struct_class.fields.first => 42) }\n    let(:other_object) { struct_class.new(struct_class.fields.first => Object.new) }\n\n    it_should_behave_like :abstract_struct\n\n    context 'definition' do\n\n      it 'does not register a new class when no name is given' do\n        Record.new(:foo, :bar, :baz)\n        expect(defined?(Record::Foo)).to be_falsey\n      end\n\n      it 'creates a new class when given an array of field names' do\n        clazz = Record.new(:foo, :bar, :baz)\n        expect(clazz).to be_a Class\n        expect(clazz.ancestors).to include(Functional::AbstractStruct)\n      end\n\n      it 'registers the new class with Record when given a string name and an array' do\n        Record.new('Bar', :foo, :bar, :baz)\n        expect(defined?(Record::Bar)).to eq 'constant'\n      end\n\n      it 'creates a new class when given a hash of field names and types/protocols' do\n        clazz = Record.new(foo: String, bar: String, baz: String)\n        expect(clazz).to be_a Class\n        expect(clazz.ancestors).to include(Functional::AbstractStruct)\n      end\n\n      it 'registers the new class with Record when given a string name and a hash' do\n        Record.new('Boom', foo: String, bar: String, baz: String)\n        expect(defined?(Record::Boom)).to eq 'constant'\n      end\n\n      it 'raises an exception when given a hash with an invalid type/protocol' do\n        expect {\n          Record.new(foo: 'String', bar: String, baz: String)\n        }.to raise_error(ArgumentError)\n      end\n\n      it 'raises an exception when given an invalid definition' do\n        expect {\n          Record.new(:foo, bar: String, baz: String)\n        }.to raise_error(ArgumentError)\n      end\n    end\n\n    context 'initialization' do\n\n      it 'sets all fields values to nil' do\n        fields = [:foo, :bar, :baz]\n        clazz = Record.new(*fields)\n\n        record = clazz.new\n\n        fields.each do |field|\n          expect(record.send(field)).to be_nil\n        end\n      end\n\n      it 'sets initial values based on values given at object construction' do\n        clazz = Record.new(:foo, :bar, :baz)\n        record = clazz.new(foo: 1, bar: 2, baz: 3)\n\n        expect(record.foo).to eq 1\n        expect(record.bar).to eq 2\n        expect(record.baz).to eq 3\n      end\n\n      context 'with default values' do\n\n        it 'defaults fields to values given during class creation' do\n          clazz = Record.new(:foo, :bar, :baz) do\n            default :foo, 42\n            default :bar, 'w00t!'\n          end\n\n          record = clazz.new\n          expect(record.foo).to eq 42\n          expect(record.bar).to eq 'w00t!'\n          expect(record.baz).to be_nil\n        end\n\n        it 'overrides default values with values provided at object construction' do\n          clazz = Record.new(:foo, :bar, :baz) do\n            default :foo, 42\n            default :bar, 'w00t!'\n            default :baz, :bogus\n          end\n\n          record = clazz.new(foo: 1, bar: 2)\n\n          expect(record.foo).to eq 1\n          expect(record.bar).to eq 2\n          expect(record.baz).to eq :bogus\n        end\n\n        it 'duplicates default values when assigning to a new object' do\n          original = 'Foo'\n          clazz = Record.new(:foo, :bar, :baz) do\n            default :foo, original\n          end\n\n          record = clazz.new\n          expect(record.foo).to eq original\n          expect(record.foo.object_id).to_not eql original.object_id\n        end\n\n        it 'does not conflate defaults across record classes' do\n          clazz_foo = Record.new(:foo, :bar, :baz) do\n            default :foo, 42\n          end\n\n          clazz_matz = Record.new(:foo, :bar, :baz) do\n            default :foo, 'Matsumoto'\n          end\n\n          expect(clazz_foo.new.foo).to eq 42\n          expect(clazz_matz.new.foo).to eq 'Matsumoto'\n        end\n      end\n\n      context 'with mandatory fields' do\n\n        it 'raises an exception when values for requred field are not provided' do\n          clazz = Record.new(:foo, :bar, :baz) do\n            mandatory :foo\n          end\n\n          expect {\n            clazz.new(bar: 1)\n          }.to raise_exception(ArgumentError)\n        end\n\n        it 'raises an exception when required values are nil' do\n          clazz = Record.new(:foo, :bar, :baz) do\n            mandatory :foo\n          end\n\n          expect {\n            clazz.new(foo: nil, bar: 1)\n          }.to raise_exception(ArgumentError)\n        end\n\n        it 'allows multiple required fields to be specified together' do\n          clazz = Record.new(:foo, :bar, :baz) do\n            mandatory :foo, :bar, :baz\n          end\n\n          expect {\n            clazz.new(foo: 1, bar: 2)\n          }.to raise_exception(ArgumentError)\n\n          expect {\n            clazz.new(bar: 2, baz: 3)\n          }.to raise_exception(ArgumentError)\n\n          expect {\n            clazz.new(foo: 1, bar: 2, baz: 3)\n          }.to_not raise_exception\n        end\n\n        it 'does not conflate default values across record classes' do\n          clazz_foo = Record.new(:foo, :bar, :baz) do\n            mandatory :foo\n          end\n\n          clazz_baz = Record.new(:foo, :bar, :baz) do\n            mandatory :baz\n          end\n\n          expect {\n            clazz_foo.new(foo: 42)\n          }.to_not raise_error\n\n          expect {\n            clazz_baz.new(baz: 42)\n          }.to_not raise_error\n        end\n      end\n\n      context 'with field type specification' do\n\n        let(:type_safe_definition) do\n          {foo: String, bar: Fixnum, baz: protocol}\n        end\n\n        let(:protocol){ SecureRandom.uuid.to_sym }\n\n        let(:clazz_with_protocol) do\n          Class.new do\n            def foo() nil end\n          end\n        end\n\n        let(:record_clazz) do\n          Record.new(type_safe_definition)\n        end\n\n        before(:each) do\n          Functional::SpecifyProtocol(protocol){ instance_method(:foo) }\n        end\n\n        it 'raises an exception for a value with an invalid type' do\n          expect {\n            record_clazz.new(foo: 'foo', bar: 'bar', baz: clazz_with_protocol.new)\n          }.to raise_error(ArgumentError)\n        end\n\n        it 'raises an exception for a value that does not satisfy a protocol' do\n          expect {\n            record_clazz.new(foo: 'foo', bar: 42, baz: 'baz')\n          }.to raise_error(ArgumentError)\n        end\n\n        it 'creates the object when all values match the appropriate types and protocols' do\n          record = record_clazz.new(foo: 'foo', bar: 42, baz: clazz_with_protocol.new)\n          expect(record).to be_a record_clazz\n        end\n      end\n\n      it 'allows a field to be required and have a default value' do\n        clazz = Record.new(:foo, :bar, :baz) do\n          mandatory :foo\n          default :foo, 42\n        end\n\n        expect {\n          clazz.new\n        }.to_not raise_exception\n\n        expect(clazz.new.foo).to eq 42\n      end\n\n      it 'raises an exception if the default value for a require field is nil' do\n        clazz = Record.new(:foo, :bar, :baz) do\n          mandatory :foo\n          default :foo, nil\n        end\n\n        expect {\n          clazz.new\n        }.to raise_exception(ArgumentError)\n      end\n    end\n\n    context 'subclassing' do\n\n      specify 'supports all capabilities on subclasses' do\n        record_clazz = Functional::Record.new(:first, :middle, :last, :suffix) do\n          mandatory :first, :last\n        end\n\n        clazz = Class.new(record_clazz) do\n          def full_name\n            \"#{first} #{last}\"\n          end\n\n          def formal_name\n            name = [first, middle, last].select{|s| ! s.to_s.empty?}.join(' ')\n            suffix.to_s.empty? ? name : name + \", #{suffix}\"\n          end\n        end\n\n        jerry = clazz.new(first: 'Jerry', last: \"D'Antonio\")\n        ted = clazz.new(first: 'Ted', middle: 'Theodore', last: 'Logan', suffix: 'Esq.')\n\n        expect(jerry.full_name).to eq \"Jerry D'Antonio\"\n        expect(jerry.formal_name).to eq \"Jerry D'Antonio\"\n\n        expect(ted.full_name).to eq \"Ted Logan\"\n        expect(ted.formal_name).to eq \"Ted Theodore Logan, Esq.\"\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/functional/tuple_spec.rb",
    "content": "require 'rspec/expectations'\n\nRSpec::Matchers.define :be_a_different_tuple_than do |expected|\n  match do |actual|\n    actual.is_a?(Functional::Tuple) && actual.object_id != expected.object_id\n  end\nend\n\nmodule Functional\n\n  describe Tuple do\n\n    context '#initialize' do\n\n      it 'creates an empty tuple when given no arguments' do\n        expect(Tuple.new).to be_empty\n      end\n\n      it 'creates an empty tuple when given an empty array' do\n        expect(Tuple.new([])).to be_empty\n      end\n\n      it 'creates a tuple when given a single array argument' do\n        subject = Tuple.new([:foo, :bar, :baz])\n\n        expect(subject).to_not be_empty\n        expect(subject[0]).to eq :foo\n        expect(subject[1]).to eq :bar\n        expect(subject[2]).to eq :baz\n      end\n\n      it 'creates a tuple when given a single argument that responds to #to_a' do\n        clazz = Class.new {\n          def to_a() [:foo, :bar, :baz]; end\n        }.new\n        subject = Tuple.new(clazz)\n\n        expect(subject).to_not be_empty\n        expect(subject[0]).to eq :foo\n        expect(subject[1]).to eq :bar\n        expect(subject[2]).to eq :baz\n      end\n\n      it 'raises an exception when given a non-array argument' do\n        expect {\n          Tuple.new(:foo)\n        }.to raise_error(ArgumentError)\n      end\n\n      it 'freezes the tuple' do\n        expect(Tuple.new).to be_frozen\n        expect(Tuple.new([])).to be_frozen\n        expect(Tuple.new([:foo, :bar, :baz])).to be_frozen\n      end\n    end\n\n    context '#at' do\n\n      subject { Tuple.new([:foo, :bar, :baz]) }\n\n      it 'returns the nth element when given a valid non-negative index' do\n        expect(subject.at(0)).to eq :foo\n        expect(subject.at(1)).to eq :bar\n        expect(subject.at(2)).to eq :baz\n      end\n\n      it 'returns the nth element from the end when given a valid negative index' do\n        expect(subject.at(-1)).to eq :baz\n        expect(subject.at(-2)).to eq :bar\n        expect(subject.at(-3)).to eq :foo\n      end\n\n      it 'returns nil when given a non-negative out-of-bounds index' do\n        expect(subject.at(3)).to be_nil\n      end\n\n      it 'returns nil when given a negative out-of-bounds index' do\n        expect(subject.at(-4)).to be_nil\n      end\n\n      it 'is aliased as #nth' do\n        expect(subject.nth(0)).to eq :foo\n        expect(subject.nth(1)).to eq :bar\n        expect(subject.nth(-2)).to eq :bar\n        expect(subject.nth(-3)).to eq :foo\n      end\n\n      it 'is aliased as #[]' do\n        expect(subject[0]).to eq :foo\n        expect(subject[1]).to eq :bar\n        expect(subject[-2]).to eq :bar\n        expect(subject[-3]).to eq :foo\n      end\n    end\n\n    context '#fetch' do\n\n      subject { Tuple.new([:foo, :bar, :baz]) }\n\n      it 'returns the nth element when given a valid non-negative index' do\n        expect(subject.fetch(0, 42)).to eq :foo\n        expect(subject.fetch(1, 42)).to eq :bar\n        expect(subject.fetch(2, 42)).to eq :baz\n      end\n\n      it 'returns the nth element from the end when given a valid negative index' do\n        expect(subject.fetch(-1, 42)).to eq :baz\n        expect(subject.fetch(-2, 42)).to eq :bar\n        expect(subject.fetch(-3, 42)).to eq :foo\n      end\n\n      it 'returns the given default when given a non-negative out-of-bounds index' do\n        expect(subject.fetch(3, 42)).to eq 42\n      end\n\n      it 'returns the given default when given a negative out-of-bounds index' do\n        expect(subject.fetch(-4, 42)).to eq 42\n      end\n    end\n\n    context '#length' do\n\n      it 'returns 0 for an empty tuple' do\n        expect(Tuple.new.length).to eq 0\n      end\n\n      it 'returns the length of a non-empty tuple' do\n        expect(Tuple.new([1, 2, 3]).length).to eq 3\n      end\n\n      it 'is aliased a #size' do\n        expect(Tuple.new.size).to eq 0\n        expect(Tuple.new([1, 2, 3]).size).to eq 3\n      end\n    end\n\n    context '#intersect' do\n\n      it 'returns an empty tuple when self is empty' do\n        subject = Tuple.new\n        other = Tuple.new([1, 2, 3])\n        result = subject.intersect(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to be_empty\n      end\n\n      it 'returns an empty tuple when other is empty' do\n        subject = Tuple.new([1, 2, 3])\n        other = Tuple.new\n        result = subject.intersect(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to be_empty\n      end\n\n      it 'returns a tuple with all elements common to both tuples' do\n        subject = Tuple.new([1, 2, 3])\n        other = Tuple.new([2, 3, 4])\n        result = subject.intersect(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [2, 3]\n      end\n\n      it 'removes duplicates from self' do\n        subject = Tuple.new([1, 2, 2, 3, 3, 3])\n        other = Tuple.new([2, 3, 4])\n        result = subject.intersect(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [2, 3]\n      end\n\n      it 'removes duplicates from other' do\n        subject = Tuple.new([1, 2, 3])\n        other = Tuple.new([2, 2, 3, 3, 3, 4])\n        result = subject.intersect(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [2, 3]\n      end\n\n      it 'operates on any other that responds to #to_a' do\n        subject = Tuple.new([1, 2, 3])\n        other = Class.new {\n          def to_a() [2, 3, 4]; end\n        }.new\n\n        result = subject.intersect(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [2, 3]\n      end\n\n      it 'is aliased as #&' do\n        subject = Tuple.new([1, 2, 3])\n        other = Tuple.new([2, 3, 4])\n        result = subject & other\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [2, 3]\n      end\n    end\n\n    context '#union' do\n\n      it 'returns a copy of self when other is empty' do\n        subject = Tuple.new\n        other = Tuple.new([1, 2, 3])\n        result = subject.union(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 3]\n      end\n\n      it 'returns a copy of other when self is empty' do\n        subject = Tuple.new([1, 2, 3])\n        other = Tuple.new\n        result = subject.union(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 3]\n      end\n\n      it 'returns a tuple with all elements from both tuples' do\n        subject = Tuple.new([1, 2, 3])\n        other = Tuple.new([1, 2, 3, 4])\n        result = subject.union(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 3, 4]\n      end\n\n      it 'removes duplicates from self' do\n        subject = Tuple.new([1, 2, 2, 3, 3, 3])\n        other = Tuple.new([1, 2, 3, 4])\n        result = subject.union(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 3, 4]\n      end\n\n      it 'removes duplicates from other' do\n        subject = Tuple.new([1, 2, 3, 4])\n        other = Tuple.new([1, 2, 2, 3, 3, 3])\n        result = subject.union(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 3, 4]\n      end\n\n      it 'operates on any other that responds to #to_a' do\n        subject = Tuple.new([1, 2, 3])\n        other = Class.new {\n          def to_a() [2, 3, 4]; end\n        }.new\n\n        result = subject.union(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 3, 4]\n      end\n\n      it 'is aliased as #|' do\n        subject = Tuple.new([1, 2, 3])\n        other = Tuple.new([2, 3, 4])\n        result = subject | other\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 3, 4]\n      end\n    end\n\n    context '#concat' do\n\n      it 'returns a copy of self when other is empty' do\n        subject = Tuple.new\n        other = Tuple.new([1, 2, 3])\n        result = subject.concat(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 3]\n      end\n\n      it 'returns a copy of other when self is empty' do\n        subject = Tuple.new([1, 2, 3])\n        other = Tuple.new\n        result = subject.concat(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 3]\n      end\n\n      it 'returns a new tuple containing all of self and other in order' do\n        subject = Tuple.new([1, 2, 3])\n        other = Tuple.new([4, 5, 6])\n        result = subject.concat(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 3, 4, 5, 6]\n      end\n\n      it 'does not remove duplicates from self or other' do\n        subject = Tuple.new([1, 2, 2, 3, 3, 3])\n        other = Tuple.new([4, 4, 4, 5, 5, 6])\n        result = subject.concat(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6]\n      end\n\n      it 'operates on any other that responds to #to_a' do\n        subject = Tuple.new([1, 2, 3])\n        other = Class.new {\n          def to_a() [4, 5, 6]; end\n        }.new\n\n        result = subject.concat(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 3, 4, 5, 6]\n      end\n\n      it 'is aliased as #+' do\n        subject = Tuple.new([1, 2, 2, 3, 3, 3])\n        other = Tuple.new([4, 4, 4, 5, 5, 6])\n        result = subject + other\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6]\n      end\n    end\n\n    context '#diff' do\n\n      it 'returns a copy of self when other is empty' do\n        subject = Tuple.new([1, 2, 3])\n        other = Tuple.new\n        result = subject.diff(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 3]\n      end\n\n      it 'returns an empty tuple when self is empty' do\n        subject = Tuple.new\n        other = Tuple.new([1, 2, 3])\n        result = subject.diff(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to be_empty\n      end\n\n      it 'returns an empty tuple when self and other have identical elements' do\n        subject = Tuple.new([1, 2, 3])\n        other = Tuple.new([1, 2, 3])\n        result = subject.diff(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to be_empty\n      end\n\n      it 'returns a tuple with all elements in self not also in other' do\n        subject = Tuple.new([1, 2, 3])\n        other = Tuple.new([3, 4, 5])\n        result = subject.diff(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2]\n      end\n\n      it 'removes duplicates from self when in other' do\n        subject = Tuple.new([1, 2, 3, 3, 3])\n        other = Tuple.new([3, 4, 5])\n        result = subject.diff(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2]\n      end\n\n      it 'removes duplicates from other when in self' do\n        subject = Tuple.new([1, 2, 3])\n        other = Tuple.new([3, 3, 3, 4, 5])\n        result = subject.diff(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2]\n      end\n\n      it 'operates on any other that responds to #to_a' do\n        subject = Tuple.new([1, 2, 3])\n        other = Class.new {\n          def to_a() [3, 4, 5]; end\n        }.new\n\n        result = subject.diff(other)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2]\n      end\n\n      it 'is aliased as #-' do\n        subject = Tuple.new([1, 2, 3])\n        other = Tuple.new([3, 4, 5])\n        result = subject - other\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2]\n      end\n    end\n\n    context '#repeat' do\n\n      it 'returns an empty tuple when multipled by zero' do\n        subject = Tuple.new([1, 2, 3])\n        result = subject.repeat(0)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to be_empty\n      end\n\n      it 'returns a copy of self when multipled by one' do\n        subject = Tuple.new([1, 2, 3])\n        result = subject.repeat(1)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 3]\n      end\n\n      it 'returns a tuple containing elements from self repeated n times' do\n        subject = Tuple.new([1, 2, 3])\n        result = subject.repeat(3)\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 3, 1, 2, 3, 1, 2, 3]\n      end\n\n      it 'raises an exception when given a negative argument' do\n        subject = Tuple.new([1, 2, 3])\n        expect {\n          subject.repeat(-2)\n        }.to raise_error(ArgumentError)\n      end\n\n      it 'is aliased as #*' do\n        subject = Tuple.new([1, 2, 3])\n        result = subject * 3\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 3, 1, 2, 3, 1, 2, 3]\n      end\n    end\n\n    context '#uniq' do\n\n      it 'returns a empty tuple when empty' do\n        subject = Tuple.new\n        result = subject.uniq\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to be_empty\n      end\n\n      it 'returns a copy of self when there are no duplicate elements' do\n        subject = Tuple.new([1, 2, 3])\n        result = subject.uniq\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 3]\n      end\n\n      it 'returns a new tuple with duplicates removed' do\n        subject = Tuple.new([1, 2, 2, 3, 3, 3])\n        result = subject.uniq\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq [1, 2, 3]\n      end\n    end\n\n    context '#each' do\n\n      it 'returns an Enumerable when no block given' do\n        subject = Tuple.new([1, 2, 3])\n        expect(subject.each).to be_a Enumerable\n      end\n\n      it 'enumerates over each element' do\n        result = []\n        subject = Tuple.new([1, 2, 2, 3, 3, 3])\n        subject.each{|item| result << item }\n        expect(result).to eq [1, 2, 2, 3, 3, 3]\n      end\n\n      it 'does not call the block when empty' do\n        result = false\n        Tuple.new.each{|item| expected = true}\n        expect(result).to be false\n      end\n    end\n\n    context '#each_with_index' do\n\n      it 'returns an Enumerable when no block given' do\n        subject = Tuple.new([1, 2, 3])\n        expect(subject.each_with_index).to be_a Enumerable\n      end\n\n      it 'enumerates over each element and index pair' do\n        result = {}\n        subject = Tuple.new([1, 2, 2, 3, 3, 3])\n        subject.each_with_index{|item, index| result[index] = item }\n\n        expected = {\n          0 => 1,\n          1 => 2,\n          2 => 2,\n          3 => 3,\n          4 => 3,\n          5 => 3,\n        }\n        expect(result).to eq expected\n      end\n\n      it 'does not call the block when empty' do\n        result = false\n        Tuple.new.each_with_index{|item, index| expected = true}\n        expect(result).to be false\n      end\n    end\n\n    context '#sequence' do\n\n      it 'returns an Enumerable when no block given' do\n        subject = Tuple.new([1, 2, 3])\n        expect(subject.sequence).to be_a Enumerable\n      end\n\n      it 'enumerates over each element' do\n        result = []\n        subject = Tuple.new([1, 2, 2, 3, 3, 3])\n        subject.sequence{|item, rest| result << item }\n        expect(result).to eq [1, 2, 2, 3, 3, 3]\n      end\n\n      it 'yields rest of tuple for each element' do\n        result = []\n        subject = Tuple.new([1, 2, 3, 4])\n        subject.sequence{|item, rest| result = rest; break }\n        expect(result).to eq [2, 3, 4]\n      end\n\n      it 'yields rest of tuple as a tuple' do\n        result = []\n        subject = Tuple.new([1, 2, 3, 4])\n        subject.sequence{|item, rest| result = rest; break }\n        expect(result).to be_a_different_tuple_than(subject)\n      end\n\n      it 'yields an empty tuple for rest when on last element' do\n        result = nil\n        subject = Tuple.new([1])\n        subject.sequence{|item, rest| result = rest }\n        expect(result).to be_a_different_tuple_than(subject)\n        expect(result).to eq []\n      end\n\n      it 'does not call the block when empty' do\n        result = false\n        Tuple.new.sequence{|item, rest| expected = true}\n        expect(result).to be false\n      end\n    end\n\n    context '#eql?' do\n\n      it 'returns true when compared to a tuple with identical elements' do\n        subject = Tuple.new([1, 2, 3])\n        other = Tuple.new([1, 2, 3])\n        expect(subject.eql?(other)).to be true\n      end\n\n      it 'returns false when given a tuple with different elements' do\n        subject = Tuple.new([1, 2, 3])\n        other = Tuple.new([2, 3, 4])\n        expect(subject.eql?(other)).to be false\n      end\n\n      it 'operates on any other that responds to #to_a' do\n        subject = Tuple.new([1, 2, 3])\n        other = Class.new {\n          def to_a() [1, 2, 3]; end\n        }.new\n\n        expect(subject.eql?(other)).to be true\n      end\n\n      it 'is aliased as #==' do\n        subject = Tuple.new([1, 2, 3])\n        identical = Tuple.new([1, 2, 3])\n        different = Tuple.new([2, 3, 4])\n\n        expect(subject == identical).to be true\n        expect(subject == different).to be false\n      end\n    end\n\n    context '#empty?' do\n\n      it 'returns true when there are no elements' do\n        subject = Tuple.new\n        expect(subject.empty?).to be true\n      end\n\n      it 'returns false when there are one or more elements' do\n        subject = Tuple.new([1, 2, 3])\n        expect(subject.empty?).to be false\n      end\n    end\n\n    context '#first' do\n\n      it 'returns nil when empty' do\n        subject = Tuple.new\n        expect(subject.first).to be nil\n      end\n\n      it 'returns the first element when not empty' do\n        subject = Tuple.new([1, 2, 3])\n        expect(subject.first).to eq 1\n      end\n\n      it 'is aliased as #head' do\n        expect(Tuple.new.head).to be nil\n        expect(Tuple.new([1, 2, 3]).head).to eq 1\n      end\n    end\n\n    context '#rest' do\n\n      it 'returns an empty tuple when empty' do\n        subject = Tuple.new\n        expect(subject.rest).to be_a_different_tuple_than(subject)\n        expect(subject.rest).to be_empty\n      end\n\n      it 'returns an empty tuple when there is only one item' do\n        subject = Tuple.new([1])\n        expect(subject.rest).to be_a_different_tuple_than(subject)\n        expect(subject.rest).to be_empty\n      end\n\n      it 'returns a tuple with all but the first element when not empty' do\n        subject = Tuple.new([1, 2, 3])\n        expect(subject.rest).to be_a_different_tuple_than(subject)\n        expect(subject.rest).to eq [2, 3]\n      end\n\n      it 'is aliased as #tail' do\n        expect(Tuple.new.rest).to be_a_different_tuple_than(subject)\n        expect(Tuple.new.rest).to be_empty\n        expect(Tuple.new([1, 2, 3]).rest).to be_a_different_tuple_than(subject)\n        expect(Tuple.new([1, 2, 3]).rest).to eq [2, 3]\n      end\n    end\n\n    context '#to_a' do\n\n      it 'returns an empty array when empty' do\n        subject = Tuple.new.to_a\n        expect(subject).to be_a Array\n        expect(subject).to be_empty\n      end\n\n      it 'returns an array with the same elements as self' do\n        subject = Tuple.new([1, 2, 3]).to_a\n        expect(subject).to be_a Array\n        expect(subject).to eq [1, 2, 3]\n      end\n\n      it 'returns a non-frozen array' do\n        expect(Tuple.new.to_a).to_not be_frozen\n        expect(Tuple.new([1, 2, 3]).to_a).to_not be_frozen\n      end\n\n      it 'is aliased as #to_ary' do\n        subject = Tuple.new([1, 2, 3]).to_ary\n        expect(subject).to be_a Array\n        expect(subject).to eq [1, 2, 3]\n      end\n    end\n\n    context 'reflection' do\n\n      specify '#inspect begins with the class name' do\n        subject = Tuple.new([1, 2, 3])\n        expect(subject.inspect).to match(/^#<#{described_class}:\\s+/)\n      end\n\n      specify '#inspect includes a list of all elements' do\n        subject = Tuple.new([1, 2, 3])\n        expect(subject.inspect).to match(/\\s+\\[1, 2, 3\\]>$/)\n        expect(Tuple.new.inspect).to match(/\\s+\\[\\]>$/)\n      end\n\n      specify '#to_s returns the same string an an array with the same elements' do\n        expect(Tuple.new.to_s).to eq [].to_s\n        expect(Tuple.new([1, 2, 3]).to_s).to eq [1, 2, 3].to_s\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/functional/type_check_spec.rb",
    "content": "module Functional\n\n  describe TypeCheck do\n\n    context 'Type?' do\n\n      it 'returns true when value is of any of the types' do\n        target = 'foo'\n        expect(TypeCheck.Type?(target, String, Array, Hash)).to be true\n      end\n\n      it 'returns false when value is not of any of the types' do\n        target = 'foo'\n        expect(TypeCheck.Type?(target, Fixnum, Array, Hash)).to be false\n      end\n    end\n\n    context 'Type!' do\n\n      it 'returns the value when value is of any of the types' do\n        target = 'foo'\n        expect(TypeCheck.Type!(target, String, Array, Hash)).to be target\n      end\n\n      it 'raises an exception when value is not of any of the types' do\n        target = 'foo'\n        expect {\n          TypeCheck.Type!(target, Fixnum, Array, Hash)\n        }.to raise_error(TypeError)\n      end\n    end\n\n    context 'Match?' do\n\n      it 'returns true when value is an exact match for at least one of the types' do\n        target = 'foo'\n        expect(TypeCheck.Match?(target, String, Array, Hash)).to be true\n      end\n\n      it 'returns false when value is not an exact match for at least one of the types' do\n        target = 'foo'\n        expect(TypeCheck.Match?(target, Fixnum, Array, Hash)).to be false\n      end\n    end\n\n    context 'Match!' do\n\n      it 'returns the value when value is an exact match for at least one of the types' do\n        target = 'foo'\n        expect(TypeCheck.Match!(target, String, Array, Hash)).to eq target\n      end\n\n      it 'raises an exception when value is not an exact match for at least one of the types' do\n        target = 'foo'\n        expect {\n          expect(TypeCheck.Match!(target, Fixnum, Array, Hash)).to eq target\n        }.to raise_error(TypeError)\n      end\n    end\n\n    context 'Child?' do\n\n      it 'returns true if value is a class and is also a match or subclass of one of types' do\n        target = String\n        expect(TypeCheck.Child?(target, Comparable, Array, Hash)).to be true\n      end\n\n      it 'returns false if value is not a class' do\n        target = 'foo'\n        expect(TypeCheck.Child?(target, Comparable, Array, Hash)).to be false\n      end\n\n      it 'returns false if value is not a subclass/match for any of the types' do\n        target = Fixnum\n        expect(TypeCheck.Child?(target, Symbol, Array, Hash)).to be false\n      end\n    end\n\n    context 'Child!' do\n\n      it 'returns the value if value is a class and is also a match or subclass of one of types' do\n        target = String\n        expect(TypeCheck.Child!(target, Comparable, Array, Hash)).to eq target\n      end\n\n      it 'raises an exception if value is not a class' do\n        target = 'foo'\n        expect {\n          TypeCheck.Child!(target, Comparable, Array, Hash)\n        }.to raise_error(TypeError)\n      end\n\n      it 'raises an exception if value is not a subclass/match for any of the types' do\n        target = Fixnum\n        expect {\n          TypeCheck.Child!(target, Symbol, Array, Hash)\n        }.to raise_error(TypeError)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/functional/union_spec.rb",
    "content": "require_relative 'abstract_struct_shared'\n\nmodule Functional\n\n  describe Union do\n\n    let!(:expected_fields){ [:a, :b, :c] }\n    let!(:expected_values){ [42, nil, nil] }\n\n    let(:struct_class) { Union.new(*expected_fields) }\n    let(:struct_object) { struct_class.send(struct_class.fields.first, 42) }\n    let(:other_object) { struct_class.send(struct_class.fields.first, Object.new) }\n\n    it_should_behave_like :abstract_struct\n\n    context 'definition' do\n\n      it 'registers the new class with Record when given a string name' do\n        Union.new('Foo', :foo, :bar, :baz)\n        expect(defined?(Union::Foo)).to eq 'constant'\n      end\n    end\n\n    context 'factories' do\n\n      specify 'exist for each field' do\n        expected_fields.each do |field|\n          expect(struct_class).to respond_to(field)\n        end\n      end\n\n      specify 'require a value' do\n        expected_fields.each do |field|\n          expect(struct_class.method(field).arity).to eq 1\n        end\n      end\n\n      specify 'set the field appropriately' do\n        clazz = Union.new(:foo, :bar)\n        obj = clazz.foo(10)\n        expect(obj.field).to eq :foo\n      end\n\n      specify 'set the value appropriately' do\n        clazz = Union.new(:foo, :bar)\n        obj = clazz.foo(10)\n        expect(obj.value).to eq 10\n      end\n\n      specify 'return a frozen union' do\n        clazz = Union.new(:foo, :bar)\n        expect(clazz.foo(10)).to be_frozen\n      end\n\n      specify 'force #new to be private' do\n        clazz = Union.new(:foo, :bar)\n        expect {\n          clazz.new\n        }.to raise_error(NoMethodError)\n      end\n    end\n\n    context 'readers' do\n\n      specify '#field returns the appropriate field' do\n        clazz = Union.new(:foo, :bar)\n        expect(clazz.foo(10).field).to eq :foo\n      end\n\n      specify '#value returns the appropriate field' do\n        clazz = Union.new(:foo, :bar)\n        expect(clazz.foo(10).value).to eq 10\n      end\n\n      specify 'return the appropriate value for the set field' do\n        clazz = Union.new(:foo, :bar)\n        expect(clazz.foo(10).foo).to eq 10\n      end\n\n      specify 'return nil for the unset field' do\n        clazz = Union.new(:foo, :bar, :baz)\n        expect(clazz.foo(10).bar).to be_nil\n        expect(clazz.foo(10).baz).to be_nil\n      end\n    end\n\n    context 'predicates' do\n\n      specify 'exist for each field' do\n        expected_fields.each do |field|\n          predicate = \"#{field}?\".to_sym\n          expect(struct_object).to respond_to(predicate)\n          expect(struct_object.method(predicate).arity).to eq 0\n        end\n      end\n\n      specify 'return true for the set field' do\n        clazz = Union.new(:foo, :bar)\n        expect(clazz.foo(10).foo?).to be true\n      end\n\n      specify 'return false for the unset fields' do\n        clazz = Union.new(:foo, :bar, :baz)\n        expect(clazz.foo(10).bar?).to be false\n        expect(clazz.foo(10).baz?).to be false\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/functional/value_struct_spec.rb",
    "content": "require 'ostruct'\n\nmodule Functional\n\n  describe ValueStruct do\n\n    context 'instanciation' do\n\n      specify 'raises an exception when no arguments given' do\n        expect {\n          ValueStruct.new\n        }.to raise_error(ArgumentError)\n      end\n\n      specify 'with a hash sets fields using has values' do\n        subject = ValueStruct.new(foo: 1, 'bar' => :two, baz: 'three')\n        expect(subject.foo).to eq 1\n        expect(subject.bar).to eq :two\n        expect(subject.baz).to eq 'three'\n      end\n\n      specify 'with a hash creates true predicates for has keys' do\n        subject = ValueStruct.new(foo: 1, 'bar' => :two, baz: 'three')\n        expect(subject.foo?).to be true\n        expect(subject.bar?).to be true\n        expect(subject.baz?).to be true\n      end\n\n      specify 'can be created from any object that responds to #each_pair' do\n        clazz = Class.new do\n          def each_pair(&block)\n            {answer: 42, harmless: 'mostly'}.each_pair(&block)\n          end\n        end\n        struct = clazz.new\n        subject = ValueStruct.new(struct)\n        expect(subject.answer).to eq 42\n        expect(subject.harmless).to eq 'mostly'\n      end\n\n      specify 'raises an exception if given a non-hash argument' do\n        expect {\n          ValueStruct.new(:bogus)\n        }.to raise_error(ArgumentError)\n      end\n    end\n\n    context 'set fields' do\n\n      subject { ValueStruct.new(foo: 42, bar: \"Don't Panic\") }\n\n      specify 'have a reader which returns the value' do\n        expect(subject.foo).to eq 42\n        expect(subject.bar).to eq \"Don't Panic\"\n      end\n\n      specify 'have a predicate which returns true' do\n        expect(subject.foo?).to be true\n        expect(subject.bar?).to be true\n      end\n    end\n\n    context 'unset fields' do\n\n      subject { ValueStruct.new(foo: 42, bar: \"Don't Panic\") }\n\n      specify 'have a magic predicate that always returns false' do\n        expect(subject.baz?).to be false\n      end\n    end\n\n    context 'accessors' do\n\n      let!(:field_value_pairs) { {foo: 1, bar: :two, baz: 'three'} }\n\n      subject { ValueStruct.new(field_value_pairs) }\n\n      specify '#get returns the value of a set field' do\n        expect(subject.get(:foo)).to eq 1\n      end\n\n      specify '#get returns nil for an unset field' do\n        expect(subject.get(:bogus)).to be nil\n      end\n\n      specify '#[] is an alias for #get' do\n        expect(subject[:foo]).to eq 1\n        expect(subject[:bogus]).to be nil\n      end\n\n      specify '#set? returns false for an unset field' do\n        expect(subject.set?(:harmless)).to be false\n      end\n\n      specify '#set? returns true for a field that has been set' do\n        subject = ValueStruct.new(harmless: 'mostly')\n        expect(subject.set?(:harmless)).to be true\n      end\n\n      specify '#fetch gets the value of a set field' do\n        subject = ValueStruct.new(harmless: 'mostly')\n        expect(subject.fetch(:harmless, 'extremely')).to eq 'mostly'\n      end\n\n      specify '#fetch returns the given value when the field is unset' do\n        expect(subject.fetch(:harmless, 'extremely')).to eq 'extremely'\n      end\n\n      specify '#fetch does not set an unset field' do\n        subject.fetch(:answer, 42)\n        expect {\n          subject.answer\n        }.to raise_error(NoMethodError)\n      end\n\n      specify '#to_h returns the key/value pairs for all set values' do\n        subject = ValueStruct.new(field_value_pairs)\n        expect(subject.to_h).to eq field_value_pairs\n        expect(subject.to_h).to_not be_frozen\n      end\n\n      specify '#each_pair returns an Enumerable when no block given' do\n        subject = ValueStruct.new(field_value_pairs)\n        expect(subject.each_pair).to be_a Enumerable\n      end\n\n      specify '#each_pair enumerates over each field/value pair' do\n        subject = ValueStruct.new(field_value_pairs)\n        result = {}\n\n        subject.each_pair do |field, value|\n          result[field] = value\n        end\n\n        expect(result).to eq field_value_pairs\n      end\n    end\n\n    context 'reflection' do\n\n      specify '#eql? returns true when both define the same fields with the same values' do\n        first = ValueStruct.new(foo: 1, 'bar' => :two, baz: 'three')\n        second = ValueStruct.new(foo: 1, 'bar' => :two, baz: 'three')\n\n        expect(first.eql?(second)).to be true\n        expect(first == second).to be true\n      end\n\n      specify '#eql? returns false when other has different fields defined' do\n        first = ValueStruct.new(foo: 1, 'bar' => :two, baz: 'three')\n        second = ValueStruct.new(foo: 1, 'bar' => :two)\n\n        expect(first.eql?(second)).to be false\n        expect(first == second).to be false\n      end\n\n      specify '#eql? returns false when other has different field values' do\n        first = ValueStruct.new(foo: 1, 'bar' => :two, baz: 'three')\n        second = ValueStruct.new(foo: 1, 'bar' => :two, baz: 3)\n\n        expect(first.eql?(second)).to be false\n        expect(first == second).to be false\n      end\n\n      specify '#eql? returns false when other is not a ValueStruct' do\n        attributes = {answer: 42, harmless: 'mostly'}\n        clazz = Class.new do\n          def to_h; {answer: 42, harmless: 'mostly'}; end\n        end\n\n        other = clazz.new\n        subject = ValueStruct.new(attributes)\n\n        expect(subject.eql?(other)).to be false\n        expect(subject == other).to be false\n      end\n\n      specify '#inspect begins with the class name' do\n        subject = ValueStruct.new(foo: 1, 'bar' => :two, baz: 'three')\n        expect(subject.inspect).to match(/^#<#{described_class}\\s+/)\n      end\n\n      specify '#inspect includes all field/value pairs' do\n        field_value_pairs = {foo: 1, 'bar' => :two, baz: 'three'}\n        subject = ValueStruct.new(field_value_pairs)\n\n        field_value_pairs.each do |field, value|\n          expect(subject.inspect).to match(/:#{field}=>\"?:?#{value}\"?/)\n        end\n      end\n\n      specify '#to_s returns the same value as #inspect' do\n        subject = ValueStruct.new(foo: 1, 'bar' => :two, baz: 'three')\n        expect(subject.to_s).to eq subject.inspect\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/spec_helper.rb",
    "content": "require 'simplecov'\nrequire 'coveralls'\n\nSimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[\n  SimpleCov::Formatter::HTMLFormatter,\n  Coveralls::SimpleCov::Formatter\n]\n\nSimpleCov.start do\n  project_name 'Functional Ruby'\n  add_filter '/spec/'\nend\n\n#require 'coveralls'\n#Coveralls.wear!\n#require 'codeclimate-test-reporter'\n#CodeClimate::TestReporter.start\n\nrequire 'functional'\n\n# import all the support files\nDir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each { |f| require File.expand_path(f) }\n\nRSpec.configure do |config|\n  config.order = 'random'\n\n  config.before(:suite) do\n  end\n\n  config.before(:each) do\n  end\n\n  config.after(:each) do\n  end\nend\n"
  },
  {
    "path": "spec/support/.gitignore",
    "content": ""
  },
  {
    "path": "tasks/.gitignore",
    "content": ""
  },
  {
    "path": "tasks/metrics.rake",
    "content": "desc 'Display LOC (lines of code) report'\ntask :loc do\n  sh 'countloc -r lib'\nend\n\ndesc 'Display code quality analysis report'\ntask :critic do\n  sh 'rubycritic lib --path critic'\nend\n"
  },
  {
    "path": "tasks/update_doc.rake",
    "content": "require 'yard'\nYARD::Rake::YardocTask.new\n\nroot = File.expand_path File.join(File.dirname(__FILE__), '..')\n\nnamespace :yard do\n\n  cmd = lambda do |command|\n    puts \">> executing: #{command}\"\n    system command or raise \"#{command} failed\"\n  end\n\n  desc 'Pushes generated documentation to github pages: http://jdantonio.github.io/functional-ruby/'\n  task :push => [:setup, :yard] do\n\n    message = Dir.chdir(root) do\n      `git log -n 1 --oneline`.strip\n    end\n    puts \"Generating commit: #{message}\"\n\n    Dir.chdir \"#{root}/yardoc\" do\n      cmd.call \"git add -A\"\n      cmd.call \"git commit -m '#{message}'\"\n      cmd.call 'git push origin gh-pages'\n    end\n\n  end\n\n  desc 'Setups second clone in ./yardoc dir for pushing doc to github'\n  task :setup do\n\n    unless File.exist? \"#{root}/yardoc/.git\"\n      cmd.call \"rm -rf #{root}/yardoc\" if File.exist?(\"#{root}/yardoc\")\n      Dir.chdir \"#{root}\" do\n        cmd.call 'git clone --single-branch --branch gh-pages git@github.com:jdantonio/functional-ruby.git ./yardoc'\n      end\n    end\n    Dir.chdir \"#{root}/yardoc\" do\n      cmd.call 'git fetch origin'\n      cmd.call 'git reset --hard origin/gh-pages'\n    end\n\n  end\n\nend\n"
  }
]