curryer 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f816271ae0ce4b1eb55f721b662461027ea4a630
4
+ data.tar.gz: ecc75dfcdedebc1c45002b810aca77bbc718f88d
5
+ SHA512:
6
+ metadata.gz: a43f9d75ba1b13b46b61f4c73dec7e8cf0bfa88577d7d7a2c82727f186349ef9c97bde0f48d8ad1d1e66e32ea007b43583a8dfd8ee7301e154cead7001d01fe3
7
+ data.tar.gz: a64132ec3f39e863164bfa19d1409e524362a78f63486322f04f7bba635c41c799a0b7ace927ecd5dda7e7bbaa03ff76eb4aeff7b824fc2f7652a909f7b9219e
@@ -0,0 +1,19 @@
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
18
+
19
+ vendor
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in curryer.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem "rubydoctest", "~> 1.1.3"
8
+ gem "pry"
9
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Andrew O'Brien
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.
@@ -0,0 +1,43 @@
1
+ # Curryer
2
+
3
+ The Delegator that curries!
4
+
5
+ There are often times where you have a module or class with many methods that
6
+ share the same initial arguments and you'd like to just set them once. Curryer
7
+ provides a method that allows you to generate an object that saves those first
8
+ couple arguments as its own state, while exposing the target's methods (with a
9
+ lower arity).
10
+
11
+ In functional programming, this is called "currying" or "partial evaluation".
12
+ Ruby supports this on the Proc level with Proc#curry. Currying is an important
13
+ concept and indeed serves as the theoretical basis for how computation works.
14
+ In fact, object-oriented programming is actually nothing by the combination of
15
+ structures/records/tuples and partially evaluated functions (see the second
16
+ example in lib/curryer if you don't believe me).
17
+
18
+ ## Running tests
19
+
20
+ This library uses Ruby-Doctest. After running `bundle install`, you can run
21
+ tests using `bundle exec rubydoctest lib/*.rb`.
22
+
23
+ ## Installation
24
+
25
+ Add this line to your application's Gemfile:
26
+
27
+ gem 'curryer'
28
+
29
+ And then execute:
30
+
31
+ $ bundle
32
+
33
+ Or install it yourself as:
34
+
35
+ $ gem install curryer
36
+
37
+ ## Contributing
38
+
39
+ 1. Fork it
40
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
41
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
42
+ 4. Push to the branch (`git push origin my-new-feature`)
43
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'curryer/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "curryer"
8
+ spec.version = Curryer::VERSION
9
+ spec.authors = ["Andrew O'Brien"]
10
+ spec.email = ["obrien.andrew@gmail.com"]
11
+ spec.description = %q{Currying + Delegation = Curryer}
12
+ spec.summary = %q{Allows you to easily wrap a target object with common arguments.}
13
+ spec.homepage = "https://github.com/AndrewO/curryer"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
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.3"
22
+ spec.add_development_dependency "rake"
23
+ end
@@ -0,0 +1,11 @@
1
+ class Foo
2
+ def do_stuff(a, b, c)
3
+ a + b - c
4
+ end
5
+ end
6
+
7
+ module FakeOOP
8
+ def self.full_name(first_name, last_name)
9
+ "#{first_name} #{last_name}"
10
+ end
11
+ end
@@ -0,0 +1,100 @@
1
+ require "curryer/version"
2
+ require "delegate"
3
+
4
+ module Curryer
5
+ # @param target [Object] Object whose methods will be wrapped in curried.
6
+ # versions
7
+ # @param *args [Array] The first n arguments of every wrapped method.
8
+ # @returns Curried A delegator with a set of arguments that will be used in
9
+ # every method call to its delegate.
10
+ #
11
+ # doctest_require: "../doctest_helper"
12
+ # doctest: Wrap an instantiated object.
13
+ # >> foo = Foo.new
14
+ # >> curried = Curryer.for_all(foo, 1, 2)
15
+ # >> curried.do_stuff(3)
16
+ # => 0
17
+ # >> curried.do_stuff(1)
18
+ # => 2
19
+ #
20
+ # doctest: Wrap a module with state.
21
+ # >> person = Curryer.for_all(FakeOOP, "Andrew", "O'Brien")
22
+ # >> person.full_name
23
+ # => "Andrew O'Brien"
24
+ #
25
+ # doctest: Raises ArgumentError when too many things are passed in.
26
+ # >> person = Curryer.for_all(FakeOOP, "Andrew", "O'Brien")
27
+ # >> begin; person.full_name("Jr."); rescue => e; end
28
+ # >> e.class
29
+ # => ArgumentError
30
+ #
31
+ # Look, ma! Object Oriented Programming is just degenerate Functional
32
+ # Programming!
33
+ def self.for_all(target, *args)
34
+ Curried.new(target, args)
35
+ end
36
+
37
+ # DO NOT USE. Not implemented.
38
+ #
39
+ # If this is actually needed, it opens up all sorts of questions like:
40
+ #
41
+ # 1. Should we have a CurriedClass (like DelegateClass) that defined methods
42
+ # instead of using method_missing?
43
+ # 2. Should we make a mixin that allows a compile time specification of
44
+ # currying (think Forwardable instead of Delegate)?
45
+ #
46
+ # These are some interesting routes to go down, are probably pretty easy to
47
+ # implement, and are valid use cases. I just don't have them right now. If
48
+ # you do, let me know.
49
+ def self.for_methods(object, methods, *args)
50
+ raise "Not implemented. Do you actually need this? " +
51
+ "Or should the caller switch between the un-curried object and its curried version?"
52
+ end
53
+
54
+ class Curried < Delegator
55
+ def initialize(target, args)
56
+ @target, @args = target, args
57
+ reset_cache!
58
+ end
59
+
60
+ def __get_obj__
61
+ @target
62
+ end
63
+
64
+ def __set_obj__(new_target)
65
+ reset_cache!
66
+ @target = new_target
67
+ end
68
+
69
+ # See STLIB's delegate.rb. This is mostly just an adaption of what the
70
+ # base Delegate#method_missing is doing.
71
+ def method_missing(m, *local_args, &b)
72
+ target = self.__get_obj__
73
+
74
+ # Get the method, and put a partially-evaluated version of it in the cache
75
+ # so that we don't have to re-curry future calls. Then call it with the
76
+ # local args.
77
+ if target.respond_to?(m)
78
+ result = @cache[m] ||= target.method(m).to_proc.curry[*@args]
79
+ if local_args.empty?
80
+ result
81
+ else
82
+ if result.respond_to?(:call)
83
+ result.call(*local_args)
84
+ else
85
+ raise ArgumentError, \
86
+ "Curried result #{result.inspect} is not callable but arguments #{local_args} were still given. " +
87
+ "You're trying to call the method with more arguments than it takes."
88
+ end
89
+ end
90
+ else
91
+ super(m, *local_args, &b)
92
+ end
93
+ end
94
+
95
+ private
96
+ def reset_cache!
97
+ @cache = {}
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,3 @@
1
+ module Curryer
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: curryer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Andrew O'Brien
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-21 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.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
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
+ description: Currying + Delegation = Curryer
42
+ email:
43
+ - obrien.andrew@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - Gemfile
50
+ - LICENSE.txt
51
+ - README.md
52
+ - Rakefile
53
+ - curryer.gemspec
54
+ - doctest_helper.rb
55
+ - lib/curryer.rb
56
+ - lib/curryer/version.rb
57
+ homepage: https://github.com/AndrewO/curryer
58
+ licenses:
59
+ - MIT
60
+ metadata: {}
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubyforge_project:
77
+ rubygems_version: 2.2.1
78
+ signing_key:
79
+ specification_version: 4
80
+ summary: Allows you to easily wrap a target object with common arguments.
81
+ test_files: []