mprelude-0.1.0/0000755000004100000410000000000015144625127013364 5ustar www-datawww-datamprelude-0.1.0/Gemfile.lock0000644000004100000410000001071715144625127015614 0ustar www-datawww-dataGIT remote: https://github.com/mbj/devtools.git revision: 26ba0a1053e6cf7b79fc72d513a73457f9a38ead ref: 26ba0a1053e6cf7b79fc72d513a73457f9a38ead specs: devtools (0.1.23) abstract_type (~> 0.0.7) adamantium (~> 0.2.0) anima (~> 0.3.0) concord (~> 0.1.5) flay (~> 2.12.0) flog (~> 4.6.2) procto (~> 0.0.3) rake (~> 12.3.0) reek (~> 5.3.0) rspec (~> 3.8.0) rspec-core (~> 3.8.0) rspec-its (~> 1.2.0) rubocop (~> 0.61.1) simplecov (~> 0.16.1) yard (~> 0.9.16) yardstick (~> 0.9.9) PATH remote: . specs: mprelude (0.0.3) abstract_type (~> 0.0.7) adamantium (~> 0.2.0) concord (~> 0.1.5) equalizer (~> 0.0.9) ice_nine (~> 0.11.1) procto (~> 0.0.2) GEM remote: https://rubygems.org/ specs: abstract_type (0.0.7) adamantium (0.2.0) ice_nine (~> 0.11.0) memoizable (~> 0.4.0) anima (0.3.1) abstract_type (~> 0.0.7) adamantium (~> 0.2) equalizer (~> 0.0.11) ast (2.4.0) axiom-types (0.1.1) descendants_tracker (~> 0.0.4) ice_nine (~> 0.11.0) thread_safe (~> 0.3, >= 0.3.1) codeclimate-engine-rb (0.4.1) virtus (~> 1.0) coercible (1.0.0) descendants_tracker (~> 0.0.1) concord (0.1.5) adamantium (~> 0.2.0) equalizer (~> 0.0.9) descendants_tracker (0.0.4) thread_safe (~> 0.3, >= 0.3.1) diff-lcs (1.3) docile (1.3.2) equalizer (0.0.11) erubis (2.7.0) flay (2.12.0) erubis (~> 2.7.0) path_expander (~> 1.0) ruby_parser (~> 3.0) sexp_processor (~> 4.0) flog (4.6.2) path_expander (~> 1.0) ruby_parser (~> 3.1, > 3.1.0) sexp_processor (~> 4.8) ice_nine (0.11.2) jaro_winkler (1.5.3) json (2.2.0) kwalify (0.7.2) memoizable (0.4.2) thread_safe (~> 0.3, >= 0.3.1) morpher (0.2.6) abstract_type (~> 0.0.7) adamantium (~> 0.2.0) anima (~> 0.3.0) ast (~> 2.2) concord (~> 0.1.5) equalizer (~> 0.0.9) ice_nine (~> 0.11.0) procto (~> 0.0.2) mutant (0.8.24) abstract_type (~> 0.0.7) adamantium (~> 0.2.0) anima (~> 0.3.0) ast (~> 2.2) concord (~> 0.1.5) diff-lcs (~> 1.3) equalizer (~> 0.0.9) ice_nine (~> 0.11.1) memoizable (~> 0.4.2) morpher (~> 0.2.6) parser (~> 2.5.1) procto (~> 0.0.2) regexp_parser (~> 1.2) unparser (~> 0.4.2) mutant-rspec (0.8.24) mutant (~> 0.8.24) rspec-core (>= 3.4.0, < 4.0.0) parallel (1.17.0) parser (2.5.3.0) ast (~> 2.4.0) path_expander (1.0.4) powerpack (0.1.2) procto (0.0.3) psych (3.1.0) rainbow (3.0.0) rake (12.3.3) reek (5.3.2) codeclimate-engine-rb (~> 0.4.0) kwalify (~> 0.7.0) parser (>= 2.5.0.0, < 2.7, != 2.5.1.1) psych (~> 3.1.0) rainbow (>= 2.0, < 4.0) regexp_parser (1.6.0) rspec (3.8.0) rspec-core (~> 3.8.0) rspec-expectations (~> 3.8.0) rspec-mocks (~> 3.8.0) rspec-core (3.8.2) rspec-support (~> 3.8.0) rspec-expectations (3.8.4) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.8.0) rspec-its (1.2.0) rspec-core (>= 3.0.0) rspec-expectations (>= 3.0.0) rspec-mocks (3.8.1) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.8.0) rspec-support (3.8.2) rubocop (0.61.1) jaro_winkler (~> 1.5.1) parallel (~> 1.10) parser (>= 2.5, != 2.5.1.1) powerpack (~> 0.1) rainbow (>= 2.2.2, < 4.0) ruby-progressbar (~> 1.7) unicode-display_width (~> 1.4.0) ruby-progressbar (1.10.1) ruby_parser (3.13.1) sexp_processor (~> 4.9) sexp_processor (4.12.1) simplecov (0.16.1) docile (~> 1.1) json (>= 1.8, < 3) simplecov-html (~> 0.10.0) simplecov-html (0.10.2) thread_safe (0.3.6) unicode-display_width (1.4.1) unparser (0.4.2) abstract_type (~> 0.0.7) adamantium (~> 0.2.0) concord (~> 0.1.5) diff-lcs (~> 1.3) equalizer (~> 0.0.9) parser (>= 2.3.1.2, < 2.6) procto (~> 0.0.2) virtus (1.0.5) axiom-types (~> 0.1) coercible (~> 1.0) descendants_tracker (~> 0.0, >= 0.0.3) equalizer (~> 0.0, >= 0.0.9) yard (0.9.20) yardstick (0.9.9) yard (~> 0.8, >= 0.8.7.2) PLATFORMS ruby DEPENDENCIES devtools! mprelude! mutant (~> 0.8.24) mutant-rspec (~> 0.8.24) BUNDLED WITH 2.0.1 mprelude-0.1.0/lib/0000755000004100000410000000000015144625127014132 5ustar www-datawww-datamprelude-0.1.0/lib/mprelude.rb0000644000004100000410000000755615144625127016311 0ustar www-datawww-data# frozen_string_literal: true require 'abstract_type' require 'adamantium' require 'concord' module MPrelude module RequireBlock include AbstractType private # Raise error unless block is provided # # @raise [MissingBlockError] # if no block is given # # @return [self] def require_block fail LocalJumpError unless block_given? self end end # RequireBLock class Maybe include( AbstractType, Adamantium::Flat, RequireBlock ) class Nothing < self instance = new define_method(:new) { instance } # Evaluate functor block # # @return [Maybe::Nothing] def fmap(&block) require_block(&block) end # Evaluate applicative block # # @return [Maybe::Nothing] def bind(&block) require_block(&block) end end # Nothing class Just < self include Concord.new(:value) # Evalute functor block # # @return [Maybe::Just] def fmap Just.new(yield(value)) end # Evalute applicative block # # @return [Maybe] def bind yield(value) end end # Just end # Maybe class Either include( AbstractType, Adamantium::Flat, Concord.new(:value), RequireBlock ) # Execute block and wrap error in left # # @param [Class] exception # # @return [Either] def self.wrap_error(*exceptions) Right.new(yield) rescue *exceptions => error Left.new(error) end # Test for left constructor # # @return [Boolean] def left? instance_of?(Left) end # Test for right constructor # # @return [Boolean] def right? instance_of?(Right) end class Left < self # Evaluate functor block # # @return [Either::Left] def fmap(&block) require_block(&block) end # Evaluate applicative block # # @return [Either::Left] def bind(&block) require_block(&block) end # Unwrap value from left # # @return [Object] def from_left value end # Unwrap value from right # # @return [Object] # # rubocop:disable Style/GuardClause def from_right if block_given? yield(value) else fail "Expected right value, got #{inspect}" end end # rubocop:enable Style/GuardClause # Map over left value # # @return [Either::Right] def lmap Left.new(yield(value)) end # Evaluate left side of branch # # @param [#call] left # @param [#call] _right def either(left, _right) left.call(value) end end # Left class Right < self # Evaluate functor block # # @return [Either::Right] def fmap Right.new(yield(value)) end # Evaluate applicative block # # @return [Either] def bind yield(value) end # Unwrap value from left # # @return [Object] # # rubocop:disable Style/GuardClause def from_left if block_given? yield(value) else fail "Expected left value, got #{inspect}" end end # rubocop:enable Style/GuardClause # Unwrap value from right # # @return [Object] def from_right value end # Map over left value # # @return [Either::Right] def lmap(&block) require_block(&block) end # Evaluate right side of branch # # @param [#call] _left # @param [#call] right def either(_left, right) right.call(value) end end # Right end # Either end # MPrelude mprelude-0.1.0/spec/0000755000004100000410000000000015144625127014316 5ustar www-datawww-datamprelude-0.1.0/spec/spec_helper.rb0000644000004100000410000000176415144625127017144 0ustar www-datawww-data# frozen_string_literal: true require 'mprelude' RSpec.shared_examples 'no block evaluation' do context 'with block' do let(:block) { -> { fail } } it 'does not evaluate block' do apply end end end RSpec.shared_examples 'requires block' do context 'without block' do let(:block) { nil } specify do expect { apply }.to raise_error(LocalJumpError) end end end RSpec.shared_examples 'returns self' do it 'returns self' do expect(apply).to be(subject) end end RSpec.shared_examples '#bind block evaluation' do it 'evaluates block and returns its wrapped result' do expect { expect(apply).to eql(block_result) } .to change(yields, :to_a) .from([]) .to([value]) end end RSpec.shared_examples 'Functor#fmap block evaluation' do it 'evaluates block and returns its wrapped result' do expect { expect(apply).to eql(described_class.new(block_result)) } .to change(yields, :to_a) .from([]) .to([value]) end end mprelude-0.1.0/spec/unit/0000755000004100000410000000000015144625127015275 5ustar www-datawww-datamprelude-0.1.0/spec/unit/mprelude/0000755000004100000410000000000015144625127017112 5ustar www-datawww-datamprelude-0.1.0/spec/unit/mprelude/maybe_spec.rb0000644000004100000410000000232715144625127021552 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe MPrelude::Maybe::Nothing do subject { described_class.new } let(:block) { -> {} } describe '#fmap' do def apply subject.fmap(&block) end include_examples 'no block evaluation' include_examples 'requires block' include_examples 'returns self' end describe '#bind' do def apply subject.bind(&block) end include_examples 'no block evaluation' include_examples 'requires block' include_examples 'returns self' end end RSpec.describe MPrelude::Maybe::Just do subject { described_class.new(value) } let(:block_result) { instance_double(Object, 'block result') } let(:value) { instance_double(Object, 'value') } let(:yields) { [] } let(:block) do lambda do |value| yields << value block_result end end describe '#fmap' do def apply subject.fmap(&block) end include_examples 'requires block' include_examples 'Functor#fmap block evaluation' end describe '#bind' do def apply subject.bind(&block) end include_examples 'requires block' include_examples '#bind block evaluation' end end mprelude-0.1.0/spec/unit/mprelude/either_spec.rb0000644000004100000410000001614315144625127021736 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe MPrelude::Either do describe '.wrap_error' do let(:block) { -> { fail error } } let(:error) { exception.new } let(:exception) { TestError } let(:other_exception) { OtherTestError } class TestError < RuntimeError; end class OtherTestError < RuntimeError; end shared_examples 'block returns' do let(:value) { instance_double(Object, 'value') } let(:block) { -> { value } } it 'returns right wrapping block value' do expect(apply).to eql(described_class::Right.new(value)) end end shared_examples 'covered exception' do it 'returns left wrapping exception' do expect(apply).to eql(described_class::Left.new(error)) end end shared_examples 'uncovered exception' do let(:unexpected_exception) { StandardError } let(:block) { -> { fail unexpected_exception } } it 'returns raises error' do expect { apply }.to raise_error(unexpected_exception) end end context 'on single exception argument' do def apply described_class.wrap_error(exception, &block) end context 'when block returns' do include_examples 'block returns' end context 'when block raises' do context 'with covered exception' do include_examples 'covered exception' end context 'with uncovered exception' do include_examples 'uncovered exception' end end end context 'on multiple exception arguments' do def apply described_class.wrap_error(exception, other_exception, &block) end context 'when block returns' do include_examples 'block returns' end context 'when block raises' do context 'with covered exception' do include_examples 'covered exception' end context 'with uncovered exception' do include_examples 'uncovered exception' end context 'with other covered exception' do let(:block) { -> { fail other_error } } let(:other_error) { other_exception.new } it 'returns left wrapping exception' do expect(apply).to eql(described_class::Left.new(other_error)) end end end end end end RSpec.describe MPrelude::Either::Left do subject { described_class.new(value) } let(:block_result) { instance_double(Object, 'block result') } let(:value) { instance_double(Object, 'value') } let(:yields) { [] } let(:block) do lambda do |value| yields << value block_result end end class TestError < RuntimeError; end describe '#fmap' do def apply subject.fmap(&block) end include_examples 'no block evaluation' include_examples 'requires block' include_examples 'returns self' end describe '#bind' do def apply subject.bind(&block) end include_examples 'no block evaluation' include_examples 'requires block' include_examples 'returns self' end describe '#from_left' do def apply subject.from_left(&block) end it 'returns left value' do expect(apply).to be(value) end include_examples 'no block evaluation' end describe '#from_right' do def apply subject.from_right(&block) end context 'without block' do let(:block) { nil } it 'raises RuntimeError error' do expect { apply }.to raise_error( RuntimeError, "Expected right value, got #{subject.inspect}" ) end end context 'with block' do let(:yields) { [] } let(:block_return) { instance_double(Object, 'block-return') } let(:block) do lambda do |value| yields << value block_return end end it 'calls block with left value' do expect { apply }.to change(yields, :to_a).from([]).to([value]) end it 'returns block value' do expect(apply).to be(block_return) end end end describe '#lmap' do def apply subject.lmap(&block) end include_examples 'requires block' include_examples 'Functor#fmap block evaluation' end describe '#either' do def apply subject.either(block, -> { fail }) end include_examples '#bind block evaluation' end describe '#left?' do def apply subject.left? end it 'returns true' do expect(apply).to be(true) end end describe '#right?' do def apply subject.right? end it 'returns false' do expect(apply).to be(false) end end end RSpec.describe MPrelude::Either::Right do subject { described_class.new(value) } let(:block_result) { instance_double(Object, 'block result') } let(:value) { instance_double(Object, 'value') } let(:yields) { [] } let(:block) do lambda do |value| yields << value block_result end end describe '#fmap' do def apply subject.fmap(&block) end include_examples 'requires block' include_examples 'Functor#fmap block evaluation' end describe '#bind' do def apply subject.bind(&block) end include_examples 'requires block' include_examples '#bind block evaluation' end describe '#from_left' do def apply subject.from_left(&block) end context 'without block' do let(:block) { nil } it 'raises RuntimeError error' do expect { apply }.to raise_error( RuntimeError, "Expected left value, got #{subject.inspect}" ) end end context 'with block' do let(:yields) { [] } let(:block_return) { instance_double(Object, 'block-return') } let(:block) do lambda do |value| yields << value block_return end end it 'calls block with right value' do expect { apply }.to change(yields, :to_a).from([]).to([value]) end it 'returns block value' do expect(apply).to be(block_return) end end end describe '#from_right' do def apply subject.from_right(&block) end it 'returns right value' do expect(apply).to be(value) end include_examples 'no block evaluation' end describe '#lmap' do def apply subject.lmap(&block) end include_examples 'requires block' include_examples 'no block evaluation' it 'returns self' do expect(apply).to be(subject) end end describe '#either' do def apply subject.either(-> { fail }, block) end include_examples '#bind block evaluation' end describe '#left?' do def apply subject.left? end it 'returns false' do expect(apply).to be(false) end end describe '#right?' do def apply subject.right? end it 'returns true' do expect(apply).to be(true) end end end mprelude-0.1.0/.rspec0000644000004100000410000000011215144625127014473 0ustar www-datawww-data--color --format progress --order random --require spec_helper --warnings mprelude-0.1.0/mprelude.gemspec0000644000004100000410000000164015144625127016547 0ustar www-datawww-data# frozen_string_literal: true Gem::Specification.new do |gem| gem.name = 'mprelude' gem.version = '0.1.0' gem.authors = ['Markus Schirp'] gem.email = ['mbj@schirp-dso.com'] gem.description = 'Minimal prelude alike classes' gem.summary = 'Mostly an either type' gem.homepage = 'https://github.com/mbj/mprelude-rb' gem.licenses = 'MIT' gem.require_paths = %w[lib] gem.files = `git ls-files`.split("\n") gem.test_files = `git ls-files -- spec/unit`.split("\n") gem.extra_rdoc_files = %w[LICENSE] gem.add_runtime_dependency('abstract_type', '~> 0.0.7') gem.add_runtime_dependency('adamantium', '~> 0.2.0') gem.add_runtime_dependency('concord', '~> 0.1.5') gem.add_runtime_dependency('equalizer', '~> 0.0.9') gem.add_runtime_dependency('ice_nine', '~> 0.11.1') gem.add_runtime_dependency('procto', '~> 0.0.2') end mprelude-0.1.0/Gemfile0000644000004100000410000000043315144625127014657 0ustar www-datawww-data# frozen_string_literal: true source 'https://rubygems.org' gemspec group :development do gem 'mutant', '~> 0.8.24' gem 'mutant-rspec', '~> 0.8.24' end gem( 'devtools', git: 'https://github.com/mbj/devtools.git', ref: '26ba0a1053e6cf7b79fc72d513a73457f9a38ead' ) mprelude-0.1.0/LICENSE0000644000004100000410000000204115144625127014366 0ustar www-datawww-dataCopyright (c) 2013 Markus Schirp Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. mprelude-0.1.0/README.md0000644000004100000410000000005715144625127014645 0ustar www-datawww-data# mprelude Some foundational ruby data types.