kleisli-run 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MDE2YjNmMDJlMGFjYjc5YjAyMmJkNjQ0MWE0NWJmYTZkZmY2OGRjYw==
5
+ data.tar.gz: !binary |-
6
+ ODgxY2NkYjUwYTdhMWJkYmE5OTA4OGM3YzI5ZTRkZDQ2NDcwNDExYg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ Y2Q4NDNmMjgxZjM1OWU3MGE3NWJiZDUxNGFhNmNhZWEwNWE2ODVjZWIxOTdh
10
+ ZWJhYTNhM2JkYjk4MTFhMTA4NDMyZTBlMzkwNDBiN2JlMjM5ODFkZDgyMzVl
11
+ NTNmNDQ2OGRkOGE1YTFjOGIyZDFiZmM3MmI0ZjkwNDQ4N2QyODg=
12
+ data.tar.gz: !binary |-
13
+ NTAxMWFjY2FmODI5M2ZhMmE3NTBkOGM3MTNhNGIxNGUwODE4NThiOGY3NWYz
14
+ NjhmZjgxZGE1NDFkNDE4Yzc0NmMwMDI2NTJlYjM1Mjc0Y2U4NGEyZTdiODg4
15
+ MGUzMGY5MTdjNTc1ODE2NzcyYWIzOGQxNzEzNjM1MjA3MDYzNjc=
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in kleisli-run.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Brian Zeligson
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # Kleisli.run
2
+
3
+ Provides a ruby version of do-notation syntax for the monads provided in the
4
+ [Kleisli](https://github.com/txus/kleisli) gem.
5
+
6
+ More concise than nested fmap/binds, more readable (to me) than point-free syntax
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'kleisli-run'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install kleisli-run
21
+
22
+ ## Usage
23
+
24
+ With this gem installed, you can map over a bunch of dependent monads to
25
+ work with their inner values using a concise procedural syntax. Plenty more
26
+ examples in the tests, but here's a few basic illustrations:
27
+
28
+ ```ruby
29
+ Kleisli.run do
30
+ a from: Success(1)
31
+ b from: Success(2)
32
+ a + b
33
+ end
34
+ # Success(3)
35
+
36
+ Kleisli.run do
37
+ a from: Failure(["not gonna happen here"])
38
+ b from: Success(2)
39
+ c from: Success(5)
40
+ a + b + c
41
+ end
42
+ # Failure(["not gonna happen here"])
43
+ # note - nothing after the first line of the block is executed
44
+ ```
45
+ A few notes about the behavior within a block
46
+
47
+ * Extract values from monads using the variable from: Monad(value) syntax
48
+ * You can use method calls for the from: value, as long as they return a monad
49
+ * Inline assignment is possible eg: a = somevalue, and somevalue does not have
50
+ to be a monad, however you must call from: on at least one monad inside a
51
+ block
52
+ * Methods and values from the scope in which the block is created are given
53
+ precedence, so you cannot name values inside the block after any names
54
+ that exist in the scope where you define the block
55
+
56
+ ## Contributing
57
+
58
+ 1. Fork it ( http://github.com/<my-github-username>/kleisli-run/fork )
59
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
60
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
61
+ 4. Push to the branch (`git push origin my-new-feature`)
62
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << "test"
6
+ t.test_files = FileList['test/**/*_test.rb']
7
+ t.verbose = true
8
+ end
9
+
10
+ task :default => :test
11
+
12
+
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'kleisli/run/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "kleisli-run"
8
+ spec.version = Kleisli::Run::VERSION
9
+ spec.authors = ["Brian Zeligson"]
10
+ spec.email = ["brian.zeligson@gmail.com"]
11
+ spec.summary = %q{do notation for monads provided by the Kleisli gem}
12
+ spec.description = %q{}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "minitest"
24
+ spec.add_runtime_dependency "kleisli-validation"
25
+ end
@@ -0,0 +1,57 @@
1
+ require "kleisli/run/version"
2
+ require 'ostruct'
3
+
4
+ module Kleisli
5
+
6
+ def self.run(&block)
7
+ r = Runner.new(block.binding)
8
+ begin
9
+ res = r.instance_eval(&block)
10
+ r.start.fmap { res }
11
+ rescue MonadTerminator => ex
12
+ ex.m
13
+ end
14
+ end
15
+
16
+ class Runner
17
+ attr_reader :start
18
+
19
+ def initialize(block_binding)
20
+ @struct = OpenStruct.new
21
+ @stopped = false
22
+ @start = false
23
+ @o_self = block_binding.eval('self')
24
+ end
25
+
26
+ def extract(val, m)
27
+ called = false
28
+ @start = m unless @start
29
+ m >-> i { called = true; @struct.send("#{val}=".to_sym, i) }
30
+ raise MonadTerminator.new(m) unless called
31
+ @struct.send(val)
32
+ end
33
+
34
+ def method_missing(m, *args)
35
+ if @o_self.respond_to?(m)
36
+ return @o_self.send(m, *args)
37
+ end
38
+ if args.first.kind_of?(Hash) && args.first[:from] && args.size == 1
39
+ return extract(m, args.first[:from])
40
+ end
41
+ if args.empty?
42
+ @struct.send(m)
43
+ else
44
+ @struct.send("#{m}=".to_sym, args.first)
45
+ end
46
+ end
47
+ end
48
+
49
+ class MonadTerminator < Exception
50
+ attr_accessor :m
51
+
52
+ def initialize(msg)
53
+ super(msg)
54
+ self.m = msg
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,5 @@
1
+ module Kleisli
2
+ module Run
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,100 @@
1
+ require 'test_helper'
2
+
3
+ class RunTest < Minitest::Test
4
+
5
+ def sums(a, b)
6
+ a + b
7
+ end
8
+
9
+ def test_completion
10
+ s = Kleisli.run do
11
+ a from: Success(3)
12
+ b from: Success(4)
13
+ sums(a, b)
14
+ end
15
+ assert(Success(7), s)
16
+ end
17
+
18
+ def test_completion_mixed_types
19
+ s = Kleisli.run do
20
+ a from: Success(3)
21
+ b from: Some(4)
22
+ sums(a, b)
23
+ end
24
+ assert(Success(7), s)
25
+
26
+ s = Kleisli.run do
27
+ a from: Some(3)
28
+ b from: Success(4)
29
+ sums(a, b)
30
+ end
31
+ assert(Some(7), s)
32
+
33
+ s = Kleisli.run do
34
+ a from: Right(3)
35
+ b from: Success(4)
36
+ c from: Some(5)
37
+ sums(c, sums(a, b))
38
+ end
39
+ assert(Right(12), s)
40
+ end
41
+
42
+ def test_short_circuit
43
+ s = Kleisli.run do
44
+ a from: Some(3)
45
+ b from: None()
46
+ c from: Some(5)
47
+ sums(c, sums(a, b))
48
+ end
49
+ assert(None(), s)
50
+
51
+ s = Kleisli.run do
52
+ a from: Success(3)
53
+ b from: Failure(['nopenope'])
54
+ g from: Failure(['heyo'])
55
+ c from: Success(5)
56
+ sums(c, sums(a, b))
57
+ end
58
+ assert(Failure(['nopenope']), s)
59
+ end
60
+
61
+ def test_short_circuit_mixed_types
62
+ s = Kleisli.run do
63
+ a from: Some(3)
64
+ b from: Failure(['nopenope'])
65
+ g from: None()
66
+ c from: Success(5)
67
+ sums(c, sums(a, b))
68
+ end
69
+ assert(Failure(['nopenope']), s)
70
+ end
71
+
72
+ def test_inline_assignment
73
+ s = Kleisli.run do
74
+ a from: Some(3)
75
+ b = 4
76
+ c from: Success(5)
77
+ sums(c, sums(a, b))
78
+ end
79
+ assert(Some(12), s)
80
+
81
+ s = Kleisli.run do
82
+ a = Success(1)
83
+ b = Failure(b: "no num")
84
+ c = Failure(c: "still no num")
85
+ d from: Success(-> x, y, z { x + y + z }) * a * b * c
86
+ e = sums(d, 3)
87
+ end
88
+ assert(Failure(b: "no num", c: "still no num"), s)
89
+
90
+ s = Kleisli.run do
91
+ a = Success(1)
92
+ b = Success(2)
93
+ c = Success(3)
94
+ d from: Success(-> x, y, z { x + y + z }) * a * b * c
95
+ e = sums(d, 4)
96
+ end
97
+ assert(Success(10), s)
98
+ end
99
+
100
+ end
@@ -0,0 +1,4 @@
1
+ require 'kleisli/validation'
2
+ require 'kleisli/run'
3
+ require 'minitest'
4
+ require 'minitest/autorun'
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kleisli-run
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Brian Zeligson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: kleisli-validation
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: ''
70
+ email:
71
+ - brian.zeligson@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - kleisli-run.gemspec
82
+ - lib/kleisli/run.rb
83
+ - lib/kleisli/run/version.rb
84
+ - test/kleisli/run_test.rb
85
+ - test/test_helper.rb
86
+ homepage: ''
87
+ licenses:
88
+ - MIT
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 2.4.4
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: do notation for monads provided by the Kleisli gem
110
+ test_files:
111
+ - test/kleisli/run_test.rb
112
+ - test/test_helper.rb