augmented 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ab72b071901020afba04d0c492f1bc6363545a2b
4
+ data.tar.gz: 529677d1369c9d9125212faa80a6f71cef648e81
5
+ SHA512:
6
+ metadata.gz: 3376e35d3240db0dd12e8dca2ae0798200d8b75fda9b1a6b90d6c6638de1f5d2df8dda2d26ca0763dd8b9e20f24183c9930005f1bf5cdb168a33c2985fc2a65c
7
+ data.tar.gz: 09f783c3f13bd508fe7d012955ade5c12d7c9dce2e215fa7d065a72669567a06cad27c3478d3a391d55386a8a5a01f334c0ec696d667dd67593a6cf37b6aff0f
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ *.sublime-*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in augmented.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016 brunze
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,170 @@
1
+ # Augmented
2
+
3
+ `Augmented` is a library with some core-type utility methods that I frequently find myself copying across projects. It uses refinements instead of class modification for maximum control and an easy sleep at night.
4
+
5
+ Many of the methods in `Augmented` facilitate a more functional style of programming and cover a few tiny gaps in Ruby's solid functional support.
6
+
7
+ ## Installation
8
+
9
+ In your Gemfile:
10
+
11
+ ```ruby
12
+ gem 'augmented'
13
+ ```
14
+
15
+ Or:
16
+
17
+ $ gem install augmented
18
+
19
+ ## Usage
20
+
21
+ You have 3 ways of loading the refinements. You can load all of them at once:
22
+
23
+ ```ruby
24
+ using Augmented
25
+ ```
26
+
27
+ You can load all refinements for just one type:
28
+
29
+ ```ruby
30
+ using Augmented::Objects
31
+ using Augmented::Hashes
32
+ using Augmented::Symbols
33
+ # etc.
34
+ ```
35
+
36
+ Or you can load just the methods you need:
37
+
38
+ ```ruby
39
+ using Augmented::Objects::Pickable
40
+ using Augmented::Symbols::Arguable
41
+ using Augmented::Procs::Chainable
42
+ # etc.
43
+ ```
44
+
45
+ ## Quick Examples
46
+
47
+ ##### `Enumerator#index_by`
48
+
49
+ Builds an index of all elements of an enumerator according to the given criterion.
50
+
51
+ ```ruby
52
+ ['a', 'bb', 'ccccc'].to_enum.index_by(&:length)
53
+ # {1=>"a", 2=>"bb", 5=>"ccccc"}
54
+ ```
55
+
56
+ ##### `Hash#polymorph`
57
+
58
+ Creates an object from an Hash.
59
+
60
+ ```ruby
61
+ class Sheep
62
+ def initialize attributes
63
+ @sound = attributes[:sound]
64
+ end
65
+
66
+ def speak
67
+ puts @sound
68
+ end
69
+ end
70
+
71
+ { type: 'Sheep', sound: 'meeehh' }.polymorph.speak
72
+ # meeehh
73
+ ```
74
+
75
+ ##### `Hash#transform`, `Hash#transform!`
76
+
77
+ Recursively applies functions to a tree of hashes.
78
+
79
+ ```ruby
80
+ tree = { lorem: 'ipsum', dolor: [ { sit: 10}, { sit: 20 } ] }
81
+ triple = -> i { i * 3 }
82
+
83
+ tree.transform({ lorem: :upcase, dolor: { sit: triple } })
84
+ # {:lorem=>"IPSUM", :dolor=>[{:sit=>30}, {:sit=>60}]}
85
+ ```
86
+
87
+ ##### `Object#pick`
88
+
89
+ Calls a bunch of methods on an object and collects the results.
90
+
91
+ ```ruby
92
+ class MyThing
93
+ def lorem; 'hello'; end
94
+ def ipsum; 'cruel'; end
95
+ def dolor; 'world'; end
96
+ end
97
+
98
+ MyThing.new.pick :lorem, :dolor
99
+ # {:lorem=>"hello", :dolor=>"world"}
100
+ ```
101
+
102
+ ##### `Object#tack`
103
+
104
+ Appends a bunch of singleton methods to an object.
105
+
106
+ ```ruby
107
+ Object.new.tack(id: 11, greet: -> { puts "hello I'm #{id}" }).greet
108
+ # hello I'm 11
109
+ ```
110
+
111
+ ##### `Object#thru`
112
+
113
+ Applies a function to an object and returns the result.
114
+
115
+ ```ruby
116
+ filter_words = -> s { s.gsub(/bad/, '').squeeze(' ').strip }
117
+
118
+ 'BAD WORDS, BAD WORDS'.downcase.thru(&filter_words).capitalize
119
+ # Words, words
120
+ ```
121
+
122
+ ##### `Proc#|`
123
+
124
+ Chains several procs together so they execute from left to right.
125
+
126
+ ```ruby
127
+ sub_two = -> i { i - 2 }
128
+ triple = -> i { i * 3 }
129
+ add_twenty = -> i { i + 20 }
130
+
131
+ (sub_two | triple | add_twenty)[5]
132
+ # 29
133
+ ```
134
+
135
+ ##### `Symbol#with`
136
+
137
+ Like [`Symbol#to_proc`](http://ruby-doc.org/core-2.3.0/Symbol.html#method-i-to_proc) but allows you to pass some arguments along.
138
+
139
+ ```ruby
140
+ class Eleven
141
+ def add_many *others
142
+ 11 + others.reduce(0, :+)
143
+ end
144
+ end
145
+
146
+ :add_many.with(1, 2, 3).call(Eleven.new)
147
+ # 17
148
+ ```
149
+
150
+ ##### `Symbol#eq`, `Symbol#neq`, `Symbol#lt`, `Symbol#lte`, `Symbol#gt`, `Symbol#gte`
151
+
152
+ Creates functions that compare an object's attribute.
153
+
154
+ ```ruby
155
+ class User
156
+ def initialize name
157
+ @name = name
158
+ end
159
+ attr_reader :name
160
+ end
161
+
162
+ users = [ User.new('Marianne'), User.new('Jeremy') ]
163
+
164
+ users.find &(:name.eq 'Marianne')
165
+ # <User:0x... name='Marianne'>
166
+ ```
167
+
168
+ ## Contributing
169
+
170
+ Do you have a method you would like to see added to this library? Perhaps something you keep copying from project to project but always found too small to bother with a gem? Feel free to submit a ticket/pull request with your idea.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.pattern = 'test/**/*_test.rb'
6
+ end
data/augmented.gemspec ADDED
@@ -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 'augmented/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "augmented"
8
+ spec.version = Augmented::VERSION
9
+ spec.authors = ["bruno"]
10
+ spec.email = ["bruno@brunze.com"]
11
+ spec.summary = %q{Useful extra methods for some Ruby core types.}
12
+ spec.description = %q{Adds a few useful extra methods to some of Ruby's core types, available as refinements.}
13
+ spec.homepage = "https://github.com/brunze/augmented"
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.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ end
@@ -0,0 +1,13 @@
1
+ module Augmented
2
+ module Enumerators
3
+ module Indexing
4
+ refine Enumerator do
5
+
6
+ def index_by &criterion
7
+ Hash[ self.map(&criterion).zip(self) ]
8
+ end
9
+
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ require 'augmented/enumerators/indexing'
2
+
3
+ module Augmented
4
+ module Enumerators
5
+ include Indexing
6
+ end
7
+ end
@@ -0,0 +1,20 @@
1
+ module Augmented
2
+ module Hashes
3
+ module Polymorphable
4
+ refine Hash do
5
+
6
+ def polymorph type_attribute_name = :type
7
+ type = (type_attribute_name if Class === type_attribute_name) ||
8
+ self[type_attribute_name] ||
9
+ self[type_attribute_name.to_s]
10
+
11
+ raise ArgumentError, 'missing the type required for polymorph' if type.to_s.empty?
12
+
13
+ klass = Class === type ? type : Object.const_get(type.to_s)
14
+ klass.new self
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,67 @@
1
+ require 'augmented/procs/chainable'
2
+
3
+ module Augmented
4
+ module Hashes
5
+ module Transformable
6
+ refine Hash do
7
+
8
+ def transform transforms
9
+ Helpers.validate! transforms
10
+
11
+ transforms.each_pair.with_object({}) do |(key, procable), new_hash|
12
+ value = self[key]
13
+
14
+ if procable.kind_of?(Hash) && value.kind_of?(Hash)
15
+ new_hash[key] = value.transform procable
16
+ elsif value.respond_to? :each
17
+ new_hash[key] = value.map{ |thing| thing.transform procable }
18
+ else
19
+ new_hash[key] = Helpers.make_one_proc(procable).call value
20
+ end
21
+ end
22
+ end
23
+
24
+ def transform! transforms
25
+ Helpers.validate! transforms
26
+
27
+ transforms.each_pair do |key, procable|
28
+ value = self[key]
29
+
30
+ if procable.kind_of?(Hash) && value.kind_of?(Hash)
31
+ self[key] = value.transform! procable
32
+ elsif value.respond_to? :each
33
+ self[key] = value.each{ |thing| thing.transform! procable }
34
+ else
35
+ self[key] = Helpers.make_one_proc(procable).call value
36
+ end
37
+ end
38
+
39
+ self
40
+ end
41
+
42
+ end
43
+
44
+
45
+ module Helpers
46
+ using ::Augmented::Procs::Chainable
47
+
48
+ def self.make_one_proc thing
49
+ if thing.kind_of?(Array)
50
+ thing.map(&:to_proc).reduce{ |chain, proc| chain | proc }
51
+ else
52
+ thing.to_proc
53
+ end
54
+ end
55
+
56
+ def self.validate! transforms
57
+ unless transforms.respond_to? :each_pair
58
+ raise ArgumentError, 'transformations must be specified in a map-like collection (must have `each_pair` enumerator)'
59
+ end
60
+ end
61
+
62
+ end
63
+
64
+ private_constant :Helpers
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,9 @@
1
+ require 'augmented/hashes/polymorphable'
2
+ require 'augmented/hashes/transformable'
3
+
4
+ module Augmented
5
+ module Hashes
6
+ include Polymorphable
7
+ include Transformable
8
+ end
9
+ end
@@ -0,0 +1,33 @@
1
+ module Augmented
2
+ module Objects
3
+ module Pickable
4
+ refine Object do
5
+
6
+ def pick *picks
7
+ ensure_array = -> thing { thing.kind_of?(Array) ? thing : Array[thing] }
8
+
9
+ if self.respond_to? :each
10
+ self.map{ |thing| thing.pick *picks }
11
+ else
12
+ picks.each_with_object({}) do |pick, result|
13
+
14
+ if pick.kind_of? Hash
15
+
16
+ pick.each do |attribute, nested_picks|
17
+ result[attribute] = self.__send__(attribute.to_sym).pick *ensure_array[nested_picks]
18
+ end
19
+
20
+ else
21
+ attribute = pick
22
+
23
+ result[attribute] = self.__send__(attribute.to_sym)
24
+ end
25
+
26
+ end
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ module Augmented
2
+ module Objects
3
+ module Tackable
4
+ refine Object do
5
+
6
+ def tack **functions
7
+ functions.each_pair do |name, thing|
8
+ function = case thing
9
+ when Proc, Method, UnboundMethod then thing
10
+ else proc{ thing } end
11
+
12
+ self.define_singleton_method name, function
13
+ end
14
+
15
+ self
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,14 @@
1
+ module Augmented
2
+ module Objects
3
+ module Thru
4
+ refine Object do
5
+
6
+ # as seen on lodash: https://lodash.com/docs#thru
7
+ def thru &function
8
+ (function || :itself.to_proc).call self
9
+ end
10
+
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ require 'augmented/objects/pickable'
2
+ require 'augmented/objects/tackable'
3
+ require 'augmented/objects/thru'
4
+
5
+ module Augmented
6
+ module Objects
7
+ include Pickable
8
+ include Tackable
9
+ include Thru
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module Augmented
2
+ module Procs
3
+ module Chainable
4
+ refine Proc do
5
+
6
+ def | other
7
+ -> (*args) { other.to_proc.call self.call(*args) }
8
+ end
9
+
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ require 'augmented/procs/chainable'
2
+
3
+ module Augmented
4
+ module Procs
5
+ include Chainable
6
+ end
7
+ end
@@ -0,0 +1,14 @@
1
+ module Augmented
2
+ module Symbols
3
+ module Arguable
4
+ refine Symbol do
5
+
6
+ # credit to Uri Agassi: http://stackoverflow.com/a/23711606/2792897
7
+ def with *args, &block
8
+ -> caller, *rest { caller.__send__ self, *rest, *args, &block }
9
+ end
10
+
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,50 @@
1
+ module Augmented
2
+ module Symbols
3
+ module Comparing
4
+ refine Symbol do
5
+
6
+ def eq value = NO_VALUE
7
+ Helpers.make_compare_function self, :==, value
8
+ end
9
+
10
+ def neq value = NO_VALUE
11
+ Helpers.make_compare_function self, :!=, value
12
+ end
13
+
14
+ def lt value = NO_VALUE
15
+ Helpers.make_compare_function self, :<, value
16
+ end
17
+
18
+ def lte value = NO_VALUE
19
+ Helpers.make_compare_function self, :<=, value
20
+ end
21
+
22
+ def gt value = NO_VALUE
23
+ Helpers.make_compare_function self, :>, value
24
+ end
25
+
26
+ def gte value = NO_VALUE
27
+ Helpers.make_compare_function self, :>=, value
28
+ end
29
+
30
+ end
31
+
32
+
33
+ module Helpers
34
+
35
+ def self.make_compare_function method_name, operator, value
36
+ if value.equal? NO_VALUE
37
+ -> thing, other { thing.__send__(method_name).__send__(operator, other.__send__(method_name)) }
38
+ else
39
+ -> thing { thing.__send__(method_name).__send__(operator, value) }
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ NO_VALUE = BasicObject.new
46
+
47
+ private_constant :NO_VALUE, :Helpers
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,9 @@
1
+ require 'augmented/symbols/arguable'
2
+ require 'augmented/symbols/comparing'
3
+
4
+ module Augmented
5
+ module Symbols
6
+ include Arguable
7
+ include Comparing
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module Augmented
2
+ VERSION = "0.0.1"
3
+ end
data/lib/augmented.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'augmented/version'
2
+
3
+ require 'augmented/enumerators'
4
+ require 'augmented/hashes'
5
+ require 'augmented/objects'
6
+ require 'augmented/procs'
7
+ require 'augmented/symbols'
8
+
9
+ module Augmented
10
+ include Enumerators
11
+ include Hashes
12
+ include Objects
13
+ include Procs
14
+ include Symbols
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'minitest/autorun'
2
+ require 'augmented/enumerators/indexing'
3
+
4
+ describe Augmented::Enumerators::Indexing do
5
+ using Augmented::Enumerators::Indexing
6
+
7
+ describe '#index_by' do
8
+
9
+ it 'returns a hash keyed by the results of invoking the criterion on every collection element and the values are the last element matching the criterion' do
10
+ ['a', 'bbb', 'c', 'dd'].to_enum.index_by(&:length).must_equal({ 1 => 'c', 2 => 'dd', 3 => 'bbb' })
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,45 @@
1
+ require 'minitest/autorun'
2
+ require 'augmented/hashes/polymorphable'
3
+ require 'ostruct'
4
+
5
+ describe Augmented::Hashes::Polymorphable do
6
+ using Augmented::Hashes::Polymorphable
7
+
8
+ describe '#polymorph' do
9
+
10
+ it 'returns an object of the class specified by the `:type` attribute, initialized with the hash itself' do
11
+ object = { type: 'OpenStruct', speak: 'meeehh' }.polymorph
12
+
13
+ object.must_be_instance_of OpenStruct
14
+ object.speak.must_equal 'meeehh'
15
+ end
16
+
17
+ describe 'type attribute' do
18
+
19
+ it 'can also be a string key in the hash' do
20
+ { 'type' => 'OpenStruct' }.polymorph.must_be_instance_of OpenStruct
21
+ end
22
+
23
+ it 'can be an arbitrary attribute in the hash' do
24
+ { lorem_ipsum: 'OpenStruct' }.polymorph(:lorem_ipsum).must_be_instance_of OpenStruct
25
+ { 'lorem_ipsum' => 'OpenStruct' }.polymorph(:lorem_ipsum).must_be_instance_of OpenStruct
26
+ end
27
+
28
+ it 'can be a class' do
29
+ { type: OpenStruct }.polymorph().must_be_instance_of OpenStruct
30
+ end
31
+
32
+ it 'can be a class passed directly to the method, ignoring the type attribute in the hash' do
33
+ { type: 'TotallyIgnoredClass' }.polymorph(OpenStruct).must_be_instance_of OpenStruct
34
+ end
35
+
36
+ end
37
+
38
+ it 'raises an error if it cannot find a type class' do
39
+ proc{ {}.polymorph }.must_raise ArgumentError
40
+ proc{ { type: nil }.polymorph }.must_raise ArgumentError
41
+ end
42
+
43
+ end
44
+
45
+ end
@@ -0,0 +1,87 @@
1
+ require 'minitest/autorun'
2
+ require 'augmented/hashes/transformable'
3
+ require 'ostruct'
4
+
5
+ describe Augmented::Hashes::Transformable do
6
+ using Augmented::Hashes::Transformable
7
+
8
+ describe '#transform(!)' do
9
+
10
+ it 'mutates the values of the given keys by applying their respective procables' do
11
+ hash = { thing1: 100, thing2: OpenStruct.new(random_method_name: 900) }.freeze
12
+
13
+ new_hash = hash.transform thing1: -> i { i * 3 }, thing2: :random_method_name
14
+
15
+ new_hash[:thing1].must_equal 300
16
+ new_hash[:thing2].must_equal 900
17
+
18
+
19
+ # mutable version test:
20
+ hash = { thing1: 100, thing2: OpenStruct.new(random_method_name: 900) }
21
+
22
+ hash.transform! thing1: -> i { i * 3 }, thing2: :random_method_name
23
+
24
+ hash[:thing1].must_equal 300
25
+ hash[:thing2].must_equal 900
26
+ end
27
+
28
+ it 'applies procables recursively when given a hash' do
29
+ hash = { a: { b: { c: 100 } } }.freeze
30
+
31
+ new_hash = hash.transform({ a: { b: { c: -> i { i * 3 } } } })
32
+
33
+ new_hash[:a][:b][:c].must_equal 300
34
+
35
+
36
+ # mutable version test:
37
+ hash = { a: { b: { c: 100 } } }
38
+
39
+ hash.transform!({ a: { b: { c: -> i { i * 3 } } } })
40
+
41
+ hash[:a][:b][:c].must_equal 300
42
+ end
43
+
44
+ it 'applies procables to all elements of a collection if a value is iterable (iterable MUST be a collection of hashes)' do
45
+ hash = { a: [ { my_value: 10 }, { my_value: 20 } ] }.freeze
46
+
47
+ new_hash = hash.transform(a: { my_value: -> i { i * 3 } })
48
+
49
+ new_hash[:a].must_equal [ { my_value: 30 }, { my_value: 60 } ]
50
+
51
+
52
+ # mutable version test:
53
+ hash = { a: [ { my_value: 10 }, { my_value: 20 } ] }
54
+
55
+ hash.transform!(a: { my_value: -> i { i * 3 } })
56
+
57
+ hash[:a].must_equal [ { my_value: 30 }, { my_value: 60 } ]
58
+ end
59
+
60
+ it 'can apply several procables to a value, supplied in an array, executed from left to right' do
61
+ add_ten = -> i { i + 10 }
62
+ double = -> i { i * 2 }
63
+
64
+ hash = { a: 2.5 }.freeze
65
+
66
+ new_hash = hash.transform a: [ :to_i, add_ten, double ]
67
+
68
+ new_hash[:a].must_equal 24
69
+
70
+
71
+ # mutable version test:
72
+ hash = { a: 2.5 }
73
+
74
+ hash.transform! a: [ :to_i, add_ten, double ]
75
+
76
+ hash[:a].must_equal 24
77
+ end
78
+
79
+ it 'returns itself (mutable version only)' do
80
+ hash = {}
81
+ same_hash = hash.transform! Hash.new
82
+
83
+ same_hash.object_id.must_equal hash.object_id
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,39 @@
1
+ require 'minitest/autorun'
2
+ require 'augmented/objects/pickable'
3
+ require 'ostruct'
4
+
5
+ describe Augmented::Objects::Pickable do
6
+ using Augmented::Objects::Pickable
7
+
8
+ describe '#pick' do
9
+
10
+ it 'returns an hash with the results of invoking the list of picks in the target' do
11
+ target = OpenStruct.new aaa: 111, bbb: 222, ccc: 333
12
+
13
+ target.pick(:aaa, :ccc).must_equal({ aaa: 111, ccc: 333 })
14
+ end
15
+
16
+ it 'returns the result of invoking `pick` on every element of an enumerable target' do
17
+ target = [ OpenStruct.new(val: 11), OpenStruct.new(val: 22), OpenStruct.new(val: 33) ]
18
+
19
+ target.pick(:val).must_equal [{val: 11}, {val: 22}, {val: 33}]
20
+ end
21
+
22
+ it 'applies picks recursively when provided with hashes' do
23
+ target = OpenStruct.new(aa: (OpenStruct.new bb: (OpenStruct.new cc: 33)))
24
+
25
+ target.pick(aa: { bb: :cc }).must_equal({ aa: { bb: { cc: 33 } } })
26
+
27
+ target = OpenStruct.new(dd: OpenStruct.new(ee: 55), ff: OpenStruct.new(gg: 77))
28
+
29
+ target.pick(dd: :ee, ff: :gg).must_equal({ dd: { ee: 55 }, ff: { gg: 77 } })
30
+ end
31
+
32
+ it 'allows you to specify pick lists with arrays when picking recursively' do
33
+ target = OpenStruct.new aa: (OpenStruct.new bb: 22, cc: (OpenStruct.new dd: 44, ee: 55))
34
+
35
+ target.pick(aa: [:bb, cc: [:dd, :ee]]).must_equal({ aa: { bb: 22, cc: { dd: 44, ee: 55 } } })
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,25 @@
1
+ require 'minitest/autorun'
2
+ require 'augmented/objects/tackable'
3
+
4
+ describe Augmented::Objects::Tackable do
5
+ using Augmented::Objects::Tackable
6
+
7
+ describe '#tack' do
8
+
9
+ it 'attaches new methods to an object' do
10
+ obj = Object.new
11
+
12
+ obj.tack lorem: 123, ipsum: -> { self }
13
+
14
+ obj.lorem.must_equal 123
15
+ obj.ipsum.object_id.must_equal obj.object_id
16
+ end
17
+
18
+ it 'returns self' do
19
+ obj = Object.new
20
+ obj.tack.object_id.must_equal obj.object_id
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,22 @@
1
+ require 'minitest/autorun'
2
+ require 'augmented/objects/thru'
3
+
4
+ describe Augmented::Objects::Thru do
5
+ using Augmented::Objects::Thru
6
+
7
+ describe '#thru' do
8
+
9
+ it 'returns the result of applying the given function to the object' do
10
+ plus_10 = -> i { i + 10 }
11
+
12
+ 5.thru(&plus_10).must_equal 15
13
+ end
14
+
15
+ it 'returns the object untouched if called without arguments' do
16
+ obj = Object.new
17
+ obj.thru.object_id.must_equal obj.object_id
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,22 @@
1
+ require 'minitest/autorun'
2
+ require 'augmented/procs/chainable'
3
+
4
+ describe Augmented::Procs::Chainable do
5
+ using Augmented::Procs::Chainable
6
+
7
+ describe '#|' do
8
+
9
+ it 'returns a function that invokes from left to right' do
10
+
11
+ add_one = -> (i) { i + 1 }
12
+ triple = -> (i) { i * 3 }
13
+ sub_two = -> (i) { i - 2 }
14
+ add_twenty = -> (i) { i + 20 }
15
+
16
+ chain = add_one | triple | sub_two | add_twenty
17
+
18
+ chain.call(1).must_equal 24
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,51 @@
1
+ require 'minitest/autorun'
2
+ require 'augmented/symbols/arguable'
3
+
4
+ describe Augmented::Symbols::Arguable do
5
+ using Augmented::Symbols::Arguable
6
+
7
+ describe '#with' do
8
+
9
+ before do
10
+ @eleven = Class.new do
11
+ def add other_number
12
+ 11 + other_number
13
+ end
14
+
15
+ def add_many one_number, another_number, *many_numbers
16
+ 11 + one_number + another_number + many_numbers.reduce(0, :+)
17
+ end
18
+
19
+ def do_whatever
20
+ yield 11
21
+ end
22
+ end.new
23
+ end
24
+
25
+ it 'returns a function that calls the method named <symbol> while also passing the arguments supplied' do
26
+ :add.with(9).call(@eleven).must_equal 20
27
+ :add_many.with(3, 6, 10, 20, 50).call(@eleven).must_equal 100
28
+ end
29
+
30
+ describe 'the returned function' do
31
+
32
+ it "it preserves Symbol's `to_proc` behavior of passing extra arguments, if supplied" do
33
+ :add.to_proc.call(@eleven, 4).must_equal 15
34
+ :add.with().call(@eleven, 4).must_equal 15
35
+
36
+ :add_many.with(10, 20).call(@eleven, 4, 5).must_equal 50
37
+ end
38
+
39
+ it 'passes along the block supplied to `with`, if any' do
40
+ result = nil
41
+ set_result = -> i { result = i }
42
+
43
+ :do_whatever.with(&set_result).call(@eleven)
44
+
45
+ result.must_equal 11
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,131 @@
1
+ require 'minitest/autorun'
2
+ require 'augmented/symbols/comparing'
3
+
4
+ describe Augmented::Symbols::Comparing do
5
+ using Augmented::Symbols::Comparing
6
+
7
+ let(:dummy) { Struct.new :lorem_ipsum }
8
+
9
+ let(:thing_A) { dummy.new 123 }
10
+ let(:thing_B) { dummy.new 123 }
11
+ let(:thing_C) { dummy.new 987 }
12
+ let(:thing_D) { dummy.new 0 }
13
+
14
+ describe '#eq' do
15
+
16
+ it 'returns a function that sends <symbol> to two objects and compares the results with `==`' do
17
+ comparator = :lorem_ipsum.eq
18
+
19
+ comparator.call(thing_A, thing_B).must_equal true
20
+ comparator.call(thing_A, thing_C).must_equal false
21
+ end
22
+
23
+ it 'if you give it a value, it returns a function that sends <symbol> to an object and compares the result to a given value using `==`' do
24
+ comparator = :lorem_ipsum.eq(123)
25
+
26
+ comparator.call(thing_A).must_equal true
27
+ comparator.call(thing_C).must_equal false
28
+ end
29
+
30
+ end
31
+
32
+ describe '#neq' do
33
+
34
+ it 'returns a function that sends <symbol> to two objects and compares the results with `!=`' do
35
+ comparator = :lorem_ipsum.neq
36
+
37
+ comparator.call(thing_A, thing_B).must_equal false
38
+ comparator.call(thing_A, thing_C).must_equal true
39
+ end
40
+
41
+ it 'if you give it a value, it returns a function that sends <symbol> to an object and compares the result to a given value using `!=`' do
42
+ comparator = :lorem_ipsum.neq(123)
43
+
44
+ comparator.call(thing_A).must_equal false
45
+ comparator.call(thing_C).must_equal true
46
+ end
47
+
48
+ end
49
+
50
+ describe '#lt' do
51
+
52
+ it 'returns a function that sends <symbol> to two objects and compares the results with `<`' do
53
+ comparator = :lorem_ipsum.lt
54
+
55
+ comparator.call(thing_A, thing_B).must_equal false
56
+ comparator.call(thing_A, thing_C).must_equal true
57
+ comparator.call(thing_C, thing_B).must_equal false
58
+ end
59
+
60
+ it 'if you give it a value, it returns a function that sends <symbol> to an object and compares the result to a given value using `<`' do
61
+ comparator = :lorem_ipsum.lt(123)
62
+
63
+ comparator.call(thing_A).must_equal false
64
+ comparator.call(thing_C).must_equal false
65
+ comparator.call(thing_D).must_equal true
66
+ end
67
+
68
+ end
69
+
70
+ describe '#lte' do
71
+
72
+ it 'returns a function that sends <symbol> to two objects and compares the results with `<=`' do
73
+ comparator = :lorem_ipsum.lte
74
+
75
+ comparator.call(thing_A, thing_B).must_equal true
76
+ comparator.call(thing_A, thing_C).must_equal true
77
+ comparator.call(thing_C, thing_B).must_equal false
78
+ end
79
+
80
+ it 'if you give it a value, it returns a function that sends <symbol> to an object and compares the result to a given value using `<=`' do
81
+ comparator = :lorem_ipsum.lte(123)
82
+
83
+ comparator.call(thing_A).must_equal true
84
+ comparator.call(thing_C).must_equal false
85
+ comparator.call(thing_D).must_equal true
86
+ end
87
+
88
+ end
89
+
90
+ describe '#gt' do
91
+
92
+ it 'returns a function that sends <symbol> to two objects and compares the results with `>`' do
93
+ comparator = :lorem_ipsum.gt
94
+
95
+ comparator.call(thing_A, thing_B).must_equal false
96
+ comparator.call(thing_A, thing_C).must_equal false
97
+ comparator.call(thing_C, thing_B).must_equal true
98
+ end
99
+
100
+ it 'if you give it a value, it returns a function that sends <symbol> to an object and compares the result to a given value using `>`' do
101
+ comparator = :lorem_ipsum.gt(123)
102
+
103
+ comparator.call(thing_A).must_equal false
104
+ comparator.call(thing_C).must_equal true
105
+ comparator.call(thing_D).must_equal false
106
+ end
107
+
108
+ end
109
+
110
+ describe '#gte' do
111
+
112
+ it 'returns a function that sends <symbol> to two objects and compares the results with `>=`' do
113
+ comparator = :lorem_ipsum.gte
114
+
115
+ comparator.call(thing_A, thing_B).must_equal true
116
+ comparator.call(thing_A, thing_C).must_equal false
117
+ comparator.call(thing_C, thing_B).must_equal true
118
+ end
119
+
120
+ it 'if you give it a value, it returns a function that sends <symbol> to an object and compares the result to a given value using `>=`' do
121
+ comparator = :lorem_ipsum.gte(123)
122
+
123
+ comparator.call(thing_A).must_equal true
124
+ comparator.call(thing_C).must_equal true
125
+ comparator.call(thing_D).must_equal false
126
+ end
127
+
128
+ end
129
+
130
+
131
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: augmented
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - bruno
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-01-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.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: Adds a few useful extra methods to some of Ruby's core types, available
42
+ as refinements.
43
+ email:
44
+ - bruno@brunze.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - Gemfile
51
+ - LICENSE.txt
52
+ - README.md
53
+ - Rakefile
54
+ - augmented.gemspec
55
+ - lib/augmented.rb
56
+ - lib/augmented/enumerators.rb
57
+ - lib/augmented/enumerators/indexing.rb
58
+ - lib/augmented/hashes.rb
59
+ - lib/augmented/hashes/polymorphable.rb
60
+ - lib/augmented/hashes/transformable.rb
61
+ - lib/augmented/objects.rb
62
+ - lib/augmented/objects/pickable.rb
63
+ - lib/augmented/objects/tackable.rb
64
+ - lib/augmented/objects/thru.rb
65
+ - lib/augmented/procs.rb
66
+ - lib/augmented/procs/chainable.rb
67
+ - lib/augmented/symbols.rb
68
+ - lib/augmented/symbols/arguable.rb
69
+ - lib/augmented/symbols/comparing.rb
70
+ - lib/augmented/version.rb
71
+ - test/augmented/enumerators/indexing_test.rb
72
+ - test/augmented/hashes/polymorphable_test.rb
73
+ - test/augmented/hashes/transformable_test.rb
74
+ - test/augmented/objects/pickable_test.rb
75
+ - test/augmented/objects/tackable_test.rb
76
+ - test/augmented/objects/thru_test.rb
77
+ - test/augmented/procs/chainable_test.rb
78
+ - test/augmented/symbols/arguable_test.rb
79
+ - test/augmented/symbols/comparing_test.rb
80
+ homepage: https://github.com/brunze/augmented
81
+ licenses:
82
+ - MIT
83
+ metadata: {}
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 2.4.5
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: Useful extra methods for some Ruby core types.
104
+ test_files:
105
+ - test/augmented/enumerators/indexing_test.rb
106
+ - test/augmented/hashes/polymorphable_test.rb
107
+ - test/augmented/hashes/transformable_test.rb
108
+ - test/augmented/objects/pickable_test.rb
109
+ - test/augmented/objects/tackable_test.rb
110
+ - test/augmented/objects/thru_test.rb
111
+ - test/augmented/procs/chainable_test.rb
112
+ - test/augmented/symbols/arguable_test.rb
113
+ - test/augmented/symbols/comparing_test.rb