Runtime assertions for Ruby literal.fun
ruby
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

Initial monads

+317 -27
+1
Gemfile
··· 12 12 gem "dry-initializer" 13 13 gem "dry-types" 14 14 gem "dry-struct" 15 + gem "solargraph"
+35
Gemfile.lock
··· 16 16 remote: https://rubygems.org/ 17 17 specs: 18 18 ast (2.4.2) 19 + backport (1.2.0) 20 + benchmark (0.2.1) 19 21 benchmark-ips (2.11.0) 20 22 concurrent-ruby (1.2.2) 23 + diff-lcs (1.5.0) 21 24 dry-core (1.0.0) 22 25 concurrent-ruby (~> 1.0) 23 26 zeitwerk (~> 2.6) ··· 38 41 dry-inflector (~> 1.0) 39 42 dry-logic (~> 1.4) 40 43 zeitwerk (~> 2.6) 44 + e2mmap (0.1.0) 41 45 ice_nine (0.11.2) 46 + jaro_winkler (1.5.4) 42 47 json (2.6.3) 48 + kramdown (2.4.0) 49 + rexml 50 + kramdown-parser-gfm (1.1.0) 51 + kramdown (~> 2.0) 52 + nokogiri (1.14.3-arm64-darwin) 53 + racc (~> 1.4) 43 54 parallel (1.23.0) 44 55 parser (3.2.2.1) 45 56 ast (~> 2.4.1) 57 + racc (1.6.2) 46 58 rainbow (3.1.1) 59 + rbs (2.8.4) 47 60 regexp_parser (2.8.0) 61 + reverse_markdown (2.1.1) 62 + nokogiri 48 63 rexml (3.2.5) 49 64 rubocop (1.50.2) 50 65 json (~> 2.3) ··· 59 74 rubocop-ast (1.28.0) 60 75 parser (>= 3.2.1.0) 61 76 ruby-progressbar (1.13.0) 77 + solargraph (0.49.0) 78 + backport (~> 1.2) 79 + benchmark 80 + bundler (~> 2.0) 81 + diff-lcs (~> 1.4) 82 + e2mmap 83 + jaro_winkler (~> 1.5) 84 + kramdown (~> 2.3) 85 + kramdown-parser-gfm (~> 1.1) 86 + parser (~> 3.0) 87 + rbs (~> 2.0) 88 + reverse_markdown (~> 2.0) 89 + rubocop (~> 1.38) 90 + thor (~> 1.0) 91 + tilt (~> 2.0) 92 + yard (~> 0.9, >= 0.9.24) 93 + thor (1.2.1) 94 + tilt (2.1.0) 62 95 unicode-display_width (2.4.2) 96 + yard (0.9.34) 63 97 zeitwerk (2.6.8) 64 98 65 99 PLATFORMS ··· 73 107 green_dots! 74 108 literal! 75 109 rubocop 110 + solargraph 76 111 zeitwerk 77 112 78 113 BUNDLED WITH
-1
lib/literal.rb
··· 7 7 Loader = Zeitwerk::Loader.for_gem.tap(&:setup) 8 8 9 9 extend Literal::Types 10 - extend Literal::Monads 11 10 12 11 module Error; end 13 12
+31
lib/literal/either.rb
··· 1 1 # frozen_string_literal: true 2 2 3 3 class Literal::Either 4 + def initialize(left_type, right_type) 5 + @left_type = left_type 6 + @right_type = right_type 7 + end 8 + 9 + def inspect 10 + "Either(#{@left_type.inspect}, #{@right_type.inspect})" 11 + end 12 + 13 + def ===(either) 14 + case either 15 + when Literal::Left 16 + @left_type === either.value 17 + when Literal::Right 18 + @right_type === either.value 19 + else 20 + false 21 + end 22 + end 23 + 24 + def new(value) 25 + case value 26 + when @left_type 27 + Literal::Left.new(value) 28 + when @right_type 29 + Literal::Right.new(value) 30 + else 31 + raise Literal::TypeError, 32 + "Expected `#{value.inspect}` to be either `#{@left_type.inspect}` or `#{@right_type.inspect}`." 33 + end 34 + end 4 35 end
+11
lib/literal/either/option.rb
··· 1 + # frozen_string_literal: true 2 + 3 + class Literal::Either::Option 4 + def initialize(value) 5 + @value = value 6 + freeze 7 + end 8 + 9 + attr_reader :value 10 + attr_accessor :type 11 + end
+27
lib/literal/failure.rb
··· 1 + # frozen_string_literal: true 2 + 3 + class Literal::Failure < Literal::Result::Option 4 + def initialize(value) 5 + @value = case value 6 + when StandardError 7 + value 8 + else 9 + Literal::TypeError.new( 10 + "Expected #{value.inspect} to be a `StandardError`." 11 + ) 12 + end 13 + 14 + freeze 15 + end 16 + 17 + def failure? = true 18 + def success? = false 19 + 20 + def inspect 21 + "Literal::Failure(#{@value.inspect})" 22 + end 23 + 24 + def raise! 25 + raise @value 26 + end 27 + end
+7 -1
lib/literal/left.rb
··· 1 1 # frozen_string_literal: true 2 2 3 - class Literal::Left < Literal::Either 3 + class Literal::Left < Literal::Either::Option 4 + def left? = true 5 + def right? = false 6 + 7 + def inspect 8 + "Literal::Left(#{@value.inspect})" 9 + end 4 10 end
+1 -1
lib/literal/maybe.rb lib/literal/optional/option.rb
··· 1 1 # frozen_string_literal: true 2 2 3 - class Literal::Maybe 3 + class Literal::Optional::Option 4 4 include Literal::Monads 5 5 end
+22 -6
lib/literal/monads.rb
··· 2 2 3 3 module Literal::Monads 4 4 Nothing = Literal::Nothing.new 5 - Maybe = Nothing # `Maybe` called without anything, e.g. `Maybe(something)` is Nothing 5 + Optional = Nothing # `Maybe` called without anything, e.g. `Maybe(something)` is Nothing 6 6 7 - def Something(thing) 8 - Literal::Something.new(thing) 7 + def Some(thing) 8 + Literal::Some.new(thing) 9 9 end 10 10 11 - def Maybe(value = nil) 12 - value.nil? ? NOTHING : Something(value) 11 + def Optional(value) 12 + value.nil? ? Nothing : Some(value) 13 13 end 14 14 15 - def Either(whatever) 15 + def Either(left_type, right_type) 16 + Literal::Either.new(left_type, right_type) 17 + end 16 18 19 + def Left(value) 20 + Literal::Left.new(value) 21 + end 22 + 23 + def Right(value) 24 + Literal::Right.new(value) 25 + end 26 + 27 + def Result(type) 28 + Literal::Result.new(type) 29 + end 30 + 31 + def Try(type, &) 32 + Literal::Result.new(type).try(&) 17 33 end 18 34 end
+6 -3
lib/literal/nothing.rb
··· 1 1 # frozen_string_literal: true 2 2 3 - class Literal::Nothing < Literal::Maybe 3 + class Literal::Nothing < Literal::Optional::Option 4 4 def initialize 5 5 freeze 6 6 end ··· 17 17 end 18 18 19 19 def flat_map 20 - raise ArgumentError, "No block given" unless block_given? 21 20 self 22 21 end 23 22 24 23 def or_else(alternative) 25 - Something(alternative) 24 + if alternative.nil? 25 + self 26 + else 27 + Some(alternative) 28 + end 26 29 end 27 30 end
-1
lib/literal/operation.rb
··· 2 2 3 3 class Literal::Operation 4 4 extend Literal::Types 5 - include Literal::Monads 6 5 7 6 class << self 8 7 def call(...) = new(...).call
+22
lib/literal/optional.rb
··· 1 + # frozen_string_literal: true 2 + 3 + class Literal::Optional 4 + def initialize(type) 5 + @type = type 6 + end 7 + 8 + def inspect 9 + "Optional(#{@type.inspect})" 10 + end 11 + 12 + def ===(optional) 13 + case optional 14 + when Literal::None 15 + true 16 + when Literal::Some 17 + @type === optional.value 18 + else 19 + false 20 + end 21 + end 22 + end
+35
lib/literal/result.rb
··· 1 + # frozen_string_literal: true 2 + 3 + class Literal::Result 4 + def initialize(type) 5 + @type = type 6 + end 7 + 8 + def inspect 9 + "Result(#{@type.inspect})" 10 + end 11 + 12 + def new(value) 13 + case value 14 + when @type 15 + Literal::Success.new(value) 16 + else 17 + Literal::Failure.new(value) 18 + end 19 + end 20 + 21 + def try 22 + output = yield 23 + if @type === output 24 + Literal::Success.new(output) 25 + else 26 + Literal::Failure.new( 27 + Literal::TypeError.new( 28 + "Expected `#{output.inspect}` to be a `#{@type.inspect}`." 29 + ) 30 + ) 31 + end 32 + rescue StandardError => e 33 + Literal::Failure.new(e) 34 + end 35 + end
+7
lib/literal/result/option.rb
··· 1 + # frozen_string_literal: true 2 + 3 + class Literal::Result::Option 4 + def initialize(value) 5 + @value = value 6 + end 7 + end
+7 -1
lib/literal/right.rb
··· 1 1 # frozen_string_literal: true 2 2 3 - class Literal::Right < Literal::Either 3 + class Literal::Right < Literal::Either::Option 4 + def left? = false 5 + def right? = true 6 + 7 + def inspect 8 + "Literal::Right(#{@value.inspect})" 9 + end 4 10 end
+6 -4
lib/literal/something.rb lib/literal/some.rb
··· 1 1 # frozen_string_literal: true 2 2 3 - class Literal::Something < Literal::Maybe 3 + class Literal::Some < Literal::Optional::Option 4 4 def initialize(value) 5 5 @value = value 6 6 freeze 7 7 end 8 8 9 + attr_accessor :value 10 + 9 11 def empty? = false 10 - def inspect = "Something(#{@value.inspect})" 12 + def inspect = "Some(#{@value.inspect})" 11 13 12 14 def value_or(_fallback) 13 15 @value 14 16 end 15 17 16 18 def map 17 - Something(yield @value) 19 + Some(yield @value) 18 20 end 19 21 20 - def flatmap 22 + def flat_map 21 23 map(yield(@value)).value_or(Nothing) 22 24 end 23 25
+10
lib/literal/success.rb
··· 1 + # frozen_string_literal: true 2 + 3 + class Literal::Success < Literal::Result::Option 4 + def failure? = false 5 + def success? = true 6 + 7 + def inspect 8 + "Literal::Success(#{@value.inspect})" 9 + end 10 + end
+2
lib/literal/types.rb
··· 1 1 # frozen_string_literal: true 2 2 3 3 module Literal::Types 4 + include Literal::Monads 5 + 4 6 def _Union(*types) 5 7 raise Literal::ArgumentError, "Union type must have at least two types." if types.size < 2 6 8
+1 -1
lib/literal/types/interface_type.rb
··· 10 10 end 11 11 12 12 def ===(other) 13 - @methods.all? { |method| other.respond_to?(method) } 13 + @methods.all? { |m| other.respond_to?(m) } 14 14 end 15 15 end
+4
lib/literal/types/union_type.rb
··· 12 12 def ===(value) 13 13 @types.any? { |type| type === value } 14 14 end 15 + 16 + def nil? 17 + @types.any?(&:nil?) 18 + end 15 19 end
+31
test/literal/either.rb
··· 1 + # frozen_string_literal: true 2 + 3 + include Literal::Monads 4 + 5 + describe "Either(Integer, String)" do 6 + let def either = Either(Integer, String) 7 + 8 + let def left = either.new(1) 9 + let def right = either.new("foo") 10 + 11 + test "left" do 12 + expect(left).to_be :left? 13 + expect(right).not_to_be :left? 14 + end 15 + 16 + test "right" do 17 + expect(right).to_be :right? 18 + expect(left).not_to_be :right? 19 + end 20 + 21 + test "===" do 22 + assert either === left 23 + assert either === right 24 + 25 + refute either === 1 26 + refute either === "foo" 27 + 28 + refute either === Literal::Left.new("foo") 29 + refute either === Literal::Right.new(1) 30 + end 31 + end
+9 -8
test/literal/operation.rb
··· 1 1 # frozen_string_literal: true 2 + # # frozen_string_literal: true 2 3 3 - class SomeOperation < Literal::Operation 4 - def call 5 - end 6 - end 4 + # class SomeOperation < Literal::Operation 5 + # def call 6 + # end 7 + # end 7 8 8 - test do 9 - result = SomeOperation.call 10 - binding.irb 11 - end 9 + # test do 10 + # result = SomeOperation.call 11 + # binding.irb 12 + # end
+42
test/literal/result.rb
··· 1 + # frozen_string_literal: true 2 + 3 + include Literal::Monads 4 + 5 + describe "Result(String)" do 6 + let def result = Result(String) 7 + let def success = result.new("Foo") 8 + let def failure 9 + result.new( 10 + StandardError.new("Bar") 11 + ) 12 + end 13 + 14 + describe ".try" do 15 + test "with correct type" do 16 + expect(result.try { "Foo" }).to_be :success? 17 + end 18 + 19 + test "with incorrect type" do 20 + expect(result.try { 1 }).to_be :failure? 21 + end 22 + 23 + test "with raise" do 24 + expect(result.try { raise }).to_be :failure? 25 + end 26 + end 27 + 28 + test "#success?" do 29 + expect(success).to_be :success? 30 + expect(failure).not_to_be :success? 31 + end 32 + 33 + test "#failure?" do 34 + expect(failure).to_be :failure? 35 + expect(success).not_to_be :failure? 36 + end 37 + 38 + test "#inspect" do 39 + expect(success.inspect) == %(Literal::Success("Foo")) 40 + expect(failure.inspect) == "Literal::Failure(#<StandardError: Bar>)" 41 + end 42 + end