augmented 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,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