All Projects → rap1ds → Ruby Possibly

rap1ds / Ruby Possibly

Licence: mit
A maybe monad

Programming Languages

ruby
36898 projects - #4 most used programming language

Labels

Projects that are alternatives of or similar to Ruby Possibly

Patterns Cheatsheet
Software design patterns cheatsheet.
Stars: ✭ 47 (-68.46%)
Mutual labels:  pattern
Go Gopher
The Go Gopher Amigurumi Pattern
Stars: ✭ 87 (-41.61%)
Mutual labels:  pattern
Circuitbreaker.net
Circuit Breaker pattern for .NET
Stars: ✭ 116 (-22.15%)
Mutual labels:  pattern
H Regular
在日常开发中积累的110多个正则表达式,欢迎大家提PR补充
Stars: ✭ 56 (-62.42%)
Mutual labels:  pattern
Nanomatch
Fast, minimal glob matcher for node.js. Similar to micromatch, minimatch and multimatch, but without support for extended globs (extglobs), posix brackets or braces, and with complete Bash 4.3 wildcard support: ("*", "**", and "?").
Stars: ✭ 79 (-46.98%)
Mutual labels:  pattern
Tidal
Pattern language
Stars: ✭ 1,304 (+775.17%)
Mutual labels:  pattern
Naming Cheatsheet
Comprehensive language-agnostic guidelines on variables naming. Home of the A/HC/LC pattern.
Stars: ✭ 9,475 (+6259.06%)
Mutual labels:  pattern
Algorithm Pattern
算法模板,最科学的刷题方式,最快速的刷题路径,你值得拥有~
Stars: ✭ 12,970 (+8604.7%)
Mutual labels:  pattern
Globbing
Introduction to "globbing" or glob matching, a programming concept that allows "filepath expansion" and matching using wildcards.
Stars: ✭ 86 (-42.28%)
Mutual labels:  pattern
Gerstnerizer
💠 pattern generator based on the idea of the book "Forms of Colors"
Stars: ✭ 114 (-23.49%)
Mutual labels:  pattern
Motif
Recursive, data driven pattern matching for Clojure
Stars: ✭ 63 (-57.72%)
Mutual labels:  pattern
Mach7
Functional programming style pattern-matching library for C++
Stars: ✭ 1,151 (+672.48%)
Mutual labels:  pattern
Geotic
Entity Component System library for javascript
Stars: ✭ 97 (-34.9%)
Mutual labels:  pattern
Input Mask Android
User input masking library repo.
Stars: ✭ 1,060 (+611.41%)
Mutual labels:  pattern
Repository
🖖Repository Pattern in Laravel. The package allows to filter by request out-of-the-box, as well as to integrate customized criteria and any kind of filters.
Stars: ✭ 134 (-10.07%)
Mutual labels:  pattern
Bentools Etl
PHP ETL (Extract / Transform / Load) library with SOLID principles + almost no dependency.
Stars: ✭ 45 (-69.8%)
Mutual labels:  pattern
Writing It Books
프로그래머의 책쓰기: 나도 IT 책 잘 쓰면 소원이 없겠네!
Stars: ✭ 90 (-39.6%)
Mutual labels:  pattern
Designpatternsincsharp
Samples associated with Pluralsight design patterns in c# courses.
Stars: ✭ 149 (+0%)
Mutual labels:  pattern
Lockdemo
指纹识别、图形识别、aliOCR识别
Stars: ✭ 142 (-4.7%)
Mutual labels:  pattern
Pattern Matching Ts
⚡ Pattern Matching in Typescript
Stars: ✭ 107 (-28.19%)
Mutual labels:  pattern

Possibly - Maybe monad for Ruby

Travis CI Code Climate

Maybe monad implementation for Ruby

puts Maybe(User.find_by_id("123")).username.downcase.or_else { "N/A" }

=> # puts downcased username if user "123" can be found, otherwise puts "N/A"

Installation

gem install possibly

Getting started

require 'possibly'

first_name = Maybe(deep_hash)[:account][:profile][:first_name].or_else { "No first name available" }

Documentation

Maybe monad is a programming pattern that allows to treat nil values that same way as non-nil values. This is done by wrapping the value, which may or may not be nil to, a wrapper class.

The implementation includes three different classes: Maybe, Some and None. Some represents a value, None represents a non-value and Maybe is a constructor, which results either Some, or None.

Maybe("I'm a value")    => #<Some:0x007ff7a85621e0 @value="I'm a value">
Maybe(nil)              => #<None:0x007ff7a852bd20>

Both Some and None implement four trivial methods: is_some?, is_none?, get and or_else

Maybe("I'm a value").is_some?               => true
Maybe("I'm a value").is_none?               => false
Maybe(nil).is_some?                         => false
Maybe(nil).is_none?                         => true
Maybe("I'm a value").get                    => "I'm a value"
Maybe("I'm a value").or_else { "No value" } => "I'm a value"
Maybe(nil).get                              => None::ValueExpectedException: `get` called to None. A value was expected.
Maybe(nil).or_else { "No value" }           => "No value"
Maybe("I'm a value").or_raise               => "I'm a value"
Maybe(nil).or_raise                         => None::ValueExpectedException: `or_raise` called to None. A value was expected.
Maybe(nil).or_raise(ArgumentError)          => ArgumentError
Maybe("I'm a value").or_nil                 => "I'm a value"
Maybe([]).or_nil                            => nil

In addition, Some and None implement Enumerable, so all methods available for Enumerable are available for Some and None:

Maybe("Print me!").each { |v| puts v }      => it puts "Print me!"
Maybe(nil).each { |v| puts v }              => puts nothing
Maybe(4).map { |v| Math.sqrt(v) }           => #<Some:0x007ff7ac8697b8 @value=2.0>
Maybe(nil).map { |v| Math.sqrt(v) }         => #<None:0x007ff7ac809b10>
Maybe(2).inject(3) { |a, b| a + b }         => 5
None().inject(3) { |a, b| a + b }           => 3

All the other methods you call on Some are forwarded to the value.

Maybe("I'm a value").upcase                 => #<Some:0x007ffe198e6128 @value="I'M A VALUE">
Maybe(nil).upcase                           => None

Case expression

Maybe implements threequals method #===, so it can be used in case expressions:

value = Maybe([nil, 1, 2, 3, 4, 5, 6].sample)

case value
when Some
  puts "Got Some: #{value.get}"
when None
  puts "Got None"
end

If the type of Maybe is Some, you can also match the value:

value = Maybe([nil, 0, 1, 2, 3, 4, 5, 6].sample)

case value
when Some(0)
  puts "Got zero"
when Some((1..3))
  puts "Got a low number: #{value.get}"
when Some((4..6))
  puts "Got a high number: #{value.get}"
when None
  puts "Got nothing"
end

For more complicated matching you can use Procs and lambdas. Proc class aliases #=== to the #call method. In practice this means that you can use Procs and lambdas in case expressions. It works also nicely with Maybe:

even = ->(a) { a % 2 == 0 }
odd = ->(a) { a % 2 != 0 }

value = Maybe([nil, 1, 2, 3, 4, 5, 6].sample)

case value
when Some(even)
  puts "Got even value: #{value.get}"
when Some(odd)
  puts "Got odd value: #{value.get}"
when None
  puts "Got None"
end

Examples

Instead of using if-clauses to define whether a value is a nil, you can wrap the value with Maybe() and threat it the same way whether or not it is a nil

Without Maybe():

user = User.find_by_id(user_id)
number_of_friends = if user && user.friends
  user.friends.count
else
  0
end

With Maybe():

number_of_friends = Maybe(User.find_by_id(user_id)).friends.count.or_else { 0 }

Same in HAML view, without Maybe():

- if @user && @user.friends
  = @user.friends.count
- else
  0
= Maybe(@user).friends.count.or_else { 0 }

Tests

rspec spec/spec.rb

License

MIT

Author

Mikko Koski / @rap1ds

Sponsored by

Sharetribe / @sharetribe / www.sharetribe.com

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].