reactive_support 0.1.2

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: a142b1256893c0aa5c9a3f28b9eb22a4ea88ee04
4
+ data.tar.gz: 9a988e249e3c15236caeb44bd61549555532a0f7
5
+ SHA512:
6
+ metadata.gz: dc50c7a5966a2b58b7a338d9c4b045958cca11a71efe3059812125a67280f612e71359fc10f4d38a7ed7cc408d6ac7a94c6bf07c7bdced0e25b9a68643dc50c8
7
+ data.tar.gz: 6f0c09ccafbab6e586d3fd54db73587bf5806247507213ef5f53e8c1a150260efe1975354deb53a7786d198b1d40bf2a921d7bbee86edfad64d6b03cf369bc26
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,162 @@
1
+ ## Contributing to ReactiveSupport
2
+ ReactiveSupport is a small project with only one maintainer (nice to meet you),
3
+ so your contributions are much appreciated. Here are some guidelines to improve
4
+ the chances your pull request will be accepted.
5
+
6
+ #### Summary Guidelines
7
+ The more of these guidelines you read, the more likely it is your pull request
8
+ will be accepted. That said, here is the TL;DR version. (Details are available in
9
+ later sections.)
10
+
11
+ DO...
12
+ * Expand existing functionality
13
+ * Fix bugs
14
+ * Add or improve tests and documentation
15
+ * Feel free to add new files as needed(make sure to add them to the
16
+ gemspec too!)
17
+ * Keep everything consistent with the ActiveSupport API
18
+ * Include robust, passing RSpec examples with your PR
19
+ * Include extensive [RDoc](https://github.com/rdoc/rdoc) comments
20
+ * Keep your code DRY and concise - be mindful of best practices
21
+ * Familiarize yourself with the metrics used on this project
22
+ * Familiarize yourself with the vision and values of this project
23
+ * Run the full test suite before making your PR
24
+ * File an issue report or message me if you have any questions
25
+ (I don't bite!)
26
+
27
+ DON'T...
28
+ * Worry that your pull request is too small - all improvements are welcome
29
+ * Break backward compatibility
30
+ * Modify existing functionality (unless required to fix a bug)
31
+ * Add dependencies
32
+ * Add functionality that is not present in ActiveSupport
33
+ * Submit a PR with breaking changes or no passing tests
34
+ * Submit changes that only work with particular tools, gemsets,
35
+ environments, or Ruby versions
36
+
37
+ Thank you for your contributions!
38
+
39
+ #### Types of Contributions
40
+ I'll consider all contributions, but the following would be
41
+ particularly helpful.
42
+
43
+ ##### Bug fixes
44
+ If you find a bug affecting ReactiveSupport's interaction with other gems,
45
+ frameworks, tools, platforms, rubies, or environments, your issue report
46
+ or patch is much appreciated. If your fix has to do with Rails, you will
47
+ also need to explain why ReactiveSupport would be included in a Rails project
48
+ since I can't think of a reason.
49
+
50
+ ##### Additional ActiveSupport methods
51
+ Most of the ActiveRecord methods I'm including are those that I find directly
52
+ relevant to [my other project](https://github.com/danascheider/canto). I
53
+ encourage pull requests that add methods that would be useful to you or others.
54
+
55
+ ##### Additional or improved tests or docs
56
+ ReactiveSupport uses RSpec and RDoc for testing and documentation, respectively.
57
+ Improvements in coverage or quality of tests and documentation are very helpful.
58
+
59
+ #### Project Vision
60
+ Your pull request is more likely to be successful if you keep ReactiveSupport's
61
+ vision and values in mind. This gem is:
62
+
63
+ ##### Unopinionated, agnostic, and independent
64
+ ReactiveSupport is intended to provide additional, useful functionality to all
65
+ Ruby developers. Successful pull requests will work regardless of platform,
66
+ environment, tooling, or gemsets, and will do so without adding dependencies.
67
+
68
+ ##### Stable and compatible
69
+ ReactiveSupport exists so users can have access to ActiveSupport's useful methods
70
+ without relying on Rails, whose frequent changes and reorganizations can hurt
71
+ projects relying on its components. Changes you submit must not adversely affect
72
+ backwards compatibility or break existing functionality. **This is the single most
73
+ important rule for contributing to ReactiveSupport.**
74
+
75
+ ##### Functionally identical to ActiveSupport
76
+ A person should be able to learn about a ReactiveSupport method by reading the
77
+ ActiveSupport documentation on the corresponding method. Note that this rule
78
+ is subordinated to the previous one. Stability and compatibility come first, always.
79
+
80
+ ##### Test-driven and test-first
81
+ ReactiveSupport development is guided by the principles of behavior-driven
82
+ development. Look at existing spec files and notice how many examples are included
83
+ for each method. Test coverage is measured by [Coveralls](http://coveralls.io),
84
+ and 100% coverage by robust, detailed tests is the standard for this project.
85
+
86
+ ##### Well documented
87
+ [Inch CI](http://inch-ci.org) is being used to evaluate the thoroughness of
88
+ ReactiveSupport's [RDoc](https://github.com/rdoc/rdoc) documentation.
89
+ Please include detailed documentation with your pull request.
90
+
91
+ ##### Mindful of metrics
92
+ As a perfectionistic and slightly neurotic individual, I have configured the
93
+ following tools for evaluating different aspects of the ReactiveSupport gem.
94
+ Please familiarize yourself with them:
95
+ * **[Travis CI](https://travis-ci.org)** is used to ensure all tests pass.
96
+ Commits that break Travis builds make me a
97
+ [sad panda](http://www.urbandictionary.com/define.php?term=sad+panda).
98
+ * **[Coveralls](https://coveralls.io)** is used to evaluate extent of
99
+ test coverage. The goal is 100% coverage, which is an achievable goal.
100
+ * **[CodeClimate](http://codeclimate.com)** is used to evaluate code
101
+ quality. I consider a CodeClimate score below 3.5 unacceptably low for
102
+ this project. (You can easily check your fork before submitting.)
103
+ * **[Inch CI](http://inch-ci.org)** is used to evaluate documentation.
104
+ Don't worry too much about what Inch says (it's newish and buggy), but
105
+ *do* take the time to include quality docs.
106
+
107
+ #### Style Guide
108
+ Development of ReactiveSupport is guided by best practices. This is a simple
109
+ gem and it should be DRY, concise, and thoroughly documented.
110
+ Here are some of the best practices and stylistic guidelines I like my projects
111
+ to adhere to:
112
+ * `unless` is preferred to `if not`
113
+ * Single-line blocks use curly braces
114
+ * Multi-line blocks use `do`...`end` syntax
115
+ * Single quotes are preferred to double quotes when there's a choice
116
+ * Fewer lines good, more lines bad (see below for examples)
117
+ * More files are better than large files*
118
+ * RSpec `describe` and `context` blocks are good
119
+ * RSpec `let` syntax is good
120
+ * RSpec examples should have a single point of failure
121
+
122
+ And here are some smells to avoid (may be OK in some cases):
123
+ * One RSpec example has multiple points of failure
124
+ * A value is hard-coded
125
+ * A method is more than 3 lines long or contains nested conditionals or blocks
126
+
127
+ Note that monkey patching is NOT considered a smell in ReactiveSupport as long
128
+ as it solves a problem not solved within the ReactiveSupport module itself.
129
+
130
+ \* But don't forget to update the gemspec!
131
+
132
+ ##### Examples: Fewer lines good, more lines bad
133
+ Lots of things can be reduced to a single line, especially blocks and conditionals.
134
+
135
+ # This:
136
+ array.map do |num|
137
+ puts "#{num} is now #{num + 1}"
138
+ num += 1
139
+ end
140
+
141
+ # Should be turned into this:
142
+ array.map {|item| puts "#{item} is now #{item += 1}" }
143
+
144
+ # And this:
145
+ if foo.defined?
146
+ puts "It's defined!"
147
+ else
148
+ puts "It's not defined!"
149
+ end
150
+
151
+ # Should look more like this:
152
+ puts foo.defined? ? "It's defined!" : "It's not defined!"
153
+
154
+ # And finally, this:
155
+ begin
156
+ return message = foo.message
157
+ rescue
158
+ "It didn't work"
159
+ end
160
+
161
+ # Needs to be written like this:
162
+ return foo.message rescue "It didn't work!"
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Dana Scheider
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,92 @@
1
+ ## ReactiveSupport [![Build Status](https://travis-ci.org/danascheider/reactive_support.svg?branch=master)](https://travis-ci.org/danascheider/reactive_support) [![Coverage Status](https://img.shields.io/coveralls/danascheider/reactive_support.svg)](https://coveralls.io/r/danascheider/reactive_support) [![Code Climate](https://codeclimate.com/github/danascheider/reactive_support/badges/gpa.svg)](https://codeclimate.com/github/danascheider/reactive_support) [![Inline docs](http://inch-ci.org/github/danascheider/reactive_support.svg?branch=master)](http://inch-ci.org/github/danascheider/reactive_support)
2
+ The ReactiveSupport gem provides a re-implementation of certain [ActiveSupport](https://github.com/rails/activesupport)
3
+ methods, allowing them to be used outside of the Rails ecosystem. This gem can
4
+ be used in any kind of project and is not dependent on any frameworks, gemsets, etc.
5
+ To add ReactiveSupport to your project, add this to your Gemfile and run `bundle install`:
6
+ <pre><code>gem 'reactive_record', '~> 0.1.0', git: 'https://github.com/danascheider/reactive_record'</code></pre>
7
+ To install locally:
8
+ <pre><code>sudo gem install reactive_record</code></pre>
9
+ Or if you're using RVM:
10
+ <pre><code>gem install reactive_record</code></pre>
11
+ Then, in your main project file, include:
12
+ <pre><code>require 'reactive_support'</code></pre>
13
+
14
+ ### Usage
15
+ In its current version, ReactiveSupport adds methods to Ruby's `Object` class, so
16
+ once required, its methods can be used on any object within your project, including
17
+ core Ruby classes.
18
+
19
+ Currently, ReactiveSupport's methods are a strict subset of ActiveSupport's. (This may
20
+ change in future versions, or most saliently, if ActiveSupport's API changes.)
21
+ That means that, while not all ActiveSupport methods are available, those that are can,
22
+ as of September 2014, be found in ActiveSupport's API documentation with no functional
23
+ differences. (This is true of ReactiveSupport 0.1.0 and ActiveSupport 4.1.6.)
24
+
25
+ ### FAQ
26
+ ##### Why not just use ActiveSupport?
27
+ There are three main reasons why you might prefer ReactiveSupport over ActiveSupport:
28
+ 1. Stability: ReactiveSupport is intended to work independently of Rails' rapidly changing
29
+ ecosystem. ReactiveSupport methods are guaranteed not to be transferred to other
30
+ Rails modules or refactored out. While ActiveSupport may be used independently of
31
+ Rails, its developers are still primarily focused on its place within Rails.
32
+ ReactiveSupport solves that problem.
33
+ 2. Simplicity: ReactiveSupport can be added to other projects without additional abstraction
34
+ layers, and it has no dependencies outside the development and test groups. You
35
+ don't have to worry about configuration, compatibility with other gems*, or
36
+ conflicting dependencies.
37
+ 3. Transparency: Rails is an enormous gem, and gets larger and more complex with each major version.
38
+ It is also opinionated, facilitating some development approaches while making
39
+ others inordinately difficult. ReactiveSupport is not large or complicated. Any
40
+ developer can read the documentation, or even the code itself, and know exactly what
41
+ he or she is dealing with.
42
+
43
+ \* I would not recommend using it in conjunction with ActiveSupport, though.
44
+
45
+ ##### This doesn't have very many methods. What gives?
46
+ ReactiveSupport is a spinoff from my other project, [Canto](https://github.com/danascheider/canto).
47
+ Consequently, the methods it includes are primarily those that I have found a use for
48
+ in Canto. As Canto grows, and as I have time, I will add more of ActiveSupport's
49
+ numerous useful methods to ReactiveSupport. In the meantime, I welcome contributions
50
+ and will respond quickly to pull requests.
51
+
52
+ ##### Is ReactiveSupport being maintained?
53
+ Yes. Since stability is one of the main advantages of ReactiveSupport, I will be taking
54
+ an "if it ain't broke, don't fix it" approach to maintaining it. An absence of recent
55
+ contributions should not be taken to mean it has fallen off my radar.
56
+
57
+ ##### Can I use ReactiveSupport in a Sinatra project/Puppet module/system utility/etc.?
58
+ Yes. ReactiveSupport is agnostic to the characteristics of your app, and there is no
59
+ reason it cannot be used in any app where you feel it is needed.
60
+
61
+ ##### What versions of Ruby are supported?
62
+ ReactiveSupport version 0.1.0 supports Ruby versions >= 1.9.3. [Travis-CI](https://travis-ci.org/danascheider/reactive_support) is set up to run tests against the most recent version
63
+ of JRuby as well (currently 1.7.16), but tests are currently failing and frankly,
64
+ I don't know JRuby well enough to fix them. Additional Rubies
65
+ may be supported in the future. Adding such support would be a welcome contribution
66
+ to the project.
67
+
68
+ ### Contributing
69
+ Contributions are welcome and I will respond promptly to all issue reports and pull
70
+ requests. Here are some guidelines to get started; I also encourage you to read the
71
+ full CONTRIBUTING.md file to ensure your pull request will be accepted as is:
72
+ * Include passing RSpec tests with your pull request. I aim for 100% test coverage.
73
+ * Run the whole test suite before you make your PR. Make sure your changes don't
74
+ break the rest of the gem.
75
+ * Make sure your changes are consistent with the functionality of ActiveSupport.
76
+ Users should be able to learn about a ReactiveSupport method by reading the
77
+ ActiveSupport docs for the corresponding ActiveSupport method.
78
+ * Don't add any new dependencies to ReactiveSupport, or methods that are specific
79
+ to a particular framework, gemset, or type of app.
80
+ * Include documentation. ReactiveSupport uses [Inch CI](http://inch-ci.org) to
81
+ evaluate the quality of documentation. Please help make it easy for others to
82
+ use and contribute to this project.
83
+ * Keep ReactiveSupport principles - stability, simplicity, and transparency - in mind.
84
+ Ideally, contributions should uphold these principles while expanding or
85
+ enhancing functionality.
86
+
87
+ ### Resources
88
+ * The [Rails guides](http://guides.rubyonrails.org/active_support_core_extensions.html) on
89
+ ActiveRecord give information about each of ReactiveSupport's methods.
90
+ * Those interested in contributing to ReactiveSupport are encouraged read up on
91
+ [Travis CI](http://travis-ci.org), [Coveralls](http://coveralls.io),
92
+ [CodeClimate](http://codeclimate.com), and [Inch CI](http://inch-ci.org).
data/files.rb ADDED
@@ -0,0 +1,19 @@
1
+ module ReactiveSupport
2
+ def self.files
3
+ Files::FILES.flatten
4
+ end
5
+
6
+ module Files
7
+ LIB_FILES = Dir.glob('./lib/**/*.rb').sort
8
+ BASE_FILES = %w(CONTRIBUTING.md
9
+ files.rb
10
+ LICENSE
11
+ Gemfile
12
+ README.md
13
+ reactive_support.gemspec
14
+ version.rb)
15
+ SPEC_FILES = Dir.glob('./spec/**/*.rb').sort
16
+
17
+ FILES = [BASE_FILES, LIB_FILES, SPEC_FILES]
18
+ end
19
+ end
@@ -0,0 +1,41 @@
1
+ require 'reactive_support'
2
+
3
+ # The ReactiveAddOns module consists of methods I wish ActiveSupport provided.
4
+ # These methods do not adhere to the ActiveSupport API. If you wish to include
5
+ # them in your project, you will need to put this in your main project file:
6
+ # require 'reactive_support/extensions'
7
+ #
8
+ # ReactiveExtensions includes ReactiveSupport, so you will need to remove any
9
+ # requires for ReactiveSupport as it will raise a SystemStackError.
10
+
11
+ module ReactiveExtensions
12
+
13
+ # The +#try_rescue+ method extends ReactiveSupport's +#try+ method so it
14
+ # rescues NoMethodErrors and TypeErrors as well as returning +nil+ when
15
+ # called on a +nil+ value.
16
+ #
17
+ # Like the +#try+ method, +#try_rescue+ takes 1 or more arguments. The first
18
+ # argument is the method to be called on the calling object, passed as a
19
+ # symbol. The others are zero or more arguments that will be passed through to
20
+ # that method, and +&block+ is an optional block that will be similarly passed through.
21
+ #
22
+ # Example of usage identical to +#try+:
23
+ # nil.try(:map) {|a| a.to_s } # => nil
24
+ # nil.try_rescue(:map) {|a| a.to_s } # => nil
25
+ #
26
+ # Example of usage calling a method that is not defined on the calling object:
27
+ # 10.try(:to_h) # => TypeError
28
+ # 10.try_rescue(:to_h) # => nil
29
+ #
30
+ # Example of usage with invalid arguments:
31
+ # %w(foo, bar, baz).try(:join, [:hello, :world]) # => TypeError
32
+ # %w(foo, bar, baz).try_rescue(:join, [:hello, :world]) # => nil
33
+
34
+ def try_rescue(*args, &block)
35
+ self.try(*args, &block) rescue nil
36
+ end
37
+ end
38
+
39
+ class Object
40
+ include ReactiveExtensions
41
+ end
@@ -0,0 +1,34 @@
1
+ class Array
2
+
3
+ # The +#from+ method returns the tail of the array starting at the given
4
+ # +position+.
5
+ # [1, 2, 3, 4, 5].from(2) # => [3, 4, 5]
6
+ # [1, 2, 3, 4, 5].from(0) # => [1, 2, 3, 4, 5]
7
+ # [1, 2, 3, 4, 5].from(-2) # => [4, 5]
8
+ #
9
+ # +#from+ returns an empty array if the receiving array is empty, the given
10
+ # +position+ exceeds the maximum index of the array, or the given +position+
11
+ # is lower than the array's minimum (i.e., largest negative) index.
12
+ # [].from(0) # => []
13
+ # [1, 2, 3, 4, 5].from(10) # => []
14
+ # [1, 2, 3, 4, 5].from(-10) # => []
15
+
16
+ def from(position)
17
+ self[position, length] || []
18
+ end
19
+
20
+ # The +#to+ method returns the beginning of the array up to and including
21
+ # the given +position+.
22
+ # [1, 2, 3, 4, 5].to(2) # => [1, 2, 3]
23
+ # [1, 2, 3, 4, 5].to(10) # => [1, 2, 3, 4, 5]
24
+ # [1, 2, 3, 4, 5].to(-2) # => [1, 2, 3, 4]
25
+ #
26
+ # +#to+ returns an empty array if the receiving array is empty or the given
27
+ # +position+ falls below the minimum (negative) index.
28
+ # [].to(0) # => []
29
+ # [1, 2, 3, 4, 5].to(-10) # => []
30
+
31
+ def to(position)
32
+ self[0..position]
33
+ end
34
+ end
@@ -0,0 +1,189 @@
1
+ # This file adds the +#blank?+ and +#present?+ methods to core Ruby classes
2
+ # The +#blank?+ method returns +true+ if the object is undefined, blank, false,
3
+ # empty, or nil. The +#present?+ method returns the opposite of +#blank?+
4
+
5
+ # Ruby's core String class. See documentation for version
6
+ # 2.1.3[http://ruby-doc.org/core-2.1.3/String.html],
7
+ # 2.0.0[http://ruby-doc.org/core-2.1.3/String.html], or
8
+ # 1.9.3[http://ruby-doc.org/core-2.0.0/String.html].
9
+
10
+ class String
11
+
12
+ # When called on a string, the +#blank?+ method returns +true+ if the string
13
+ # is empty or consists only of whitespace:
14
+ # ''.blank? # => true
15
+ # " \n ".blank? # => true
16
+ # 'foo'.blank? # => false
17
+
18
+ def blank?
19
+ !!(/\A[[:space:]]*\z/ =~ self) || self.empty?
20
+ end
21
+
22
+ # When called on a string, the +#present?+ method returns +true+ unless the
23
+ # string is empty or consists only of whitespace:
24
+ # 'foo'.present? # => true
25
+ # ''.present? # => false
26
+ # ' '.present? # => false
27
+
28
+ def present?
29
+ !blank?
30
+ end
31
+ end
32
+
33
+ # Ruby's core Array class. See documentation for version
34
+ # 2.1.3[http://ruby-doc.org/core-2.1.3/FalseClass.html],
35
+ # 2.0.0[http://ruby-doc.org/core-2.0.0/FalseClass.html], or
36
+ # 1.9.3[http://ruby-doc.org/core-1.9.3/FalseClass.html].
37
+
38
+ class Array
39
+
40
+ # When called on an array, the +#blank?+ method is aliased to +#empty?+
41
+ # and returns +true+ when the array has no elements. Note that +#blank?+
42
+ # returns +false+ if the array has elements that are themselves all blank:
43
+ # [].blank? # => true
44
+ # ['foo', 'bar'].blank? # => false
45
+ # [false, nil, ''].blank? # => false
46
+
47
+ alias_method :blank?, :empty?
48
+
49
+ # When called on an array, the +#present?+ method returns +true+ if the
50
+ # array has any elements. Note that +#present?+ also returns +true+ if the
51
+ # array consists of blank values:
52
+ # ['foo', 'bar'].present? # => true
53
+ # [false, nil].present? # => true
54
+ # [].present? # => false
55
+
56
+ def present?
57
+ !blank?
58
+ end
59
+ end
60
+
61
+ # Ruby's core Hash class. See documentation for version
62
+ # 2.1.3[http://ruby-doc.org/core-2.1.3/Hash.html],
63
+ # 2.0.0[http://ruby-doc.org/core-2.0.0/Hash.html], or
64
+ # 1.9.3[http://ruby-doc.org/core-1.9.3/Hash.html].
65
+
66
+ class Hash
67
+
68
+ # When called on a hash (or any enumerable), the +#blank?+ method is aliased
69
+ # to +#empty?+ and as such returns +true+ if the hash is empty:
70
+ # {}.blank? # => true
71
+ # { foo: 'bar' }.blank? # => false
72
+ # { foo: nil }.blank? # => false
73
+
74
+ alias_method :blank?, :empty?
75
+
76
+ # When called on a hash (or any enumerable), the +#present?+ method returns
77
+ # +true+ if the hash is not empty, even if its elements have blank values:
78
+ # { foo: :bar }.present? # => true
79
+ # { 'bar' => nil }.present? # => true
80
+ # {}.present? # => false
81
+
82
+ def present?
83
+ !blank?
84
+ end
85
+ end
86
+
87
+ # Ruby's core NilClass (the singleton class consisting of the +nil+ object).
88
+ # See documentation for version 2.1.3[http://ruby-doc.org/core-2.1.3/NilClass.html],
89
+ # 2.0.0[http://ruby-doc.org/core-2.0.0/NilClass.html], or
90
+ # 1.9.3[http://ruby-doc.org/core-1.9.3/NilClass.html].
91
+
92
+ class NilClass
93
+
94
+ # +nil+ is considered blank by definition; if +#blank?+ is called on +nil+,
95
+ # it will always return +true+:
96
+ # nil.blank? # => true
97
+ #
98
+ # # When the +foo+ variable is undefined or set to nil:
99
+ # foo.blank? # => true
100
+
101
+ def blank?
102
+ true
103
+ end
104
+
105
+ # Likewise, +nil+ is not present by definition; if +#present?+ is called on
106
+ # +nil+, it will always return +false+:
107
+ # nil.present? # => false
108
+ #
109
+ # # When the +foo+ variable is undefined or set to nil:
110
+ # foo.present? # => false
111
+
112
+ def present?
113
+ false
114
+ end
115
+ end
116
+
117
+ # Ruby's core TrueClass (the singleton class consisting of the +true+ object).
118
+ # See documentation for version 2.1.3[http://ruby-doc.org/core-2.1.3/TrueClass.html],
119
+ # 2.0.0[http://ruby-doc.org/core-2.0.0/TrueClass.html], or
120
+ # 1.9.3[http://ruby-doc.org/core-1.9.3/TrueClass.html].
121
+
122
+ class TrueClass
123
+
124
+ # +true+ is not blank by definition; when called on +true+, the +#blank?+
125
+ # method will return +false+:
126
+ # true.blank? # => false
127
+
128
+ def blank?
129
+ false
130
+ end
131
+
132
+ # +true+ is present by definition; when called on +true+, the +#present?+
133
+ # method will return +true+:
134
+ # true.present? # => true
135
+
136
+ def present?
137
+ true
138
+ end
139
+ end
140
+
141
+ # Ruby's core FalseClass (the singleton class consisting of the +false+ object).
142
+ # See documentation for version 2.1.3[http://ruby-doc.org/core-2.1.3/FalseClass.html],
143
+ # 2.0.0[http://ruby-doc.org/core-2.0.0/FalseClass.html], or
144
+ # 1.9.3[http://ruby-doc.org/core-1.9.3/FalseClass.html].
145
+
146
+ class FalseClass
147
+
148
+ # +false+ is blank by definition; when called on +false+, the +#blank?+
149
+ # method will return +true+:
150
+ # false.blank? # => true
151
+
152
+ def blank?
153
+ true
154
+ end
155
+
156
+ # +false+ is not present by definition; when called on +false+, the +#present?+
157
+ # method will return +false+:
158
+ # false.present? # => false
159
+
160
+ def present?
161
+ false
162
+ end
163
+ end
164
+
165
+ # Ruby's core Numeric class, the parent class of Integer, Fixnum, Bignum, Float,
166
+ # and Rational. See documentation for version 2.1.3[http://ruby-doc.org/core-2.1.3/Numeric.html],
167
+ # 2.0.0[http://ruby-doc.org/core-2.0.0/Numeric.html], or
168
+ # 1.9.3[http://ruby-doc.org/core-1.9.3/Numeric.html].
169
+
170
+ class Numeric
171
+
172
+ # Numbers can never be blank; when called on any +Numeric+ (including +Fixnum+,
173
+ # +Bignum+, +Float+, +Integer+, and +Rational+), the +#blank?+ method will
174
+ # return +false+:
175
+ # 10.blank? # => false
176
+
177
+ def blank?
178
+ false
179
+ end
180
+
181
+ # Numbers are always present; when called on any +Numeric+ (including +Fixnum+,
182
+ # +Bignum+, +Float+, +Integer+, and +Rational+), the +#present?+ method will
183
+ # return +true+:
184
+ # Math.PI.present? # => true
185
+
186
+ def present?
187
+ true
188
+ end
189
+ end
@@ -0,0 +1,54 @@
1
+ class Object
2
+
3
+ # The +#deep_dup+ method returns a duplicate of a duplicable object. If the
4
+ # object calling +#deep_dup+ is not duplicable, the object itself is returned.
5
+ # +#deep_dup+ is overwritten in the Array and Hash classes (see +./object/deep_dup.rb+).
6
+ # In those classes, it duplicates the object recursively so the members of the
7
+ # enumerable can be manipulated without affecting the original object.
8
+
9
+ def deep_dup
10
+ duplicable? ? self.dup : self
11
+ end
12
+ end
13
+
14
+ class Array
15
+
16
+ # When called on an array, the +#deep_dup+ method duplicates all the members
17
+ # of the array recursively, so that actions on the duplicate do not affect
18
+ # the original:
19
+ #
20
+ # arr = [1, 2, [3, 4]] # => [1, 2, [3, 4]]
21
+ # dup, deep = arr.dup, arr.deep_dup # => [1, 2, [3, 4]], [1, 2, [3, 4]]
22
+ #
23
+ # deep[2][1] = 5 # => [1, 2, [3, 5]]
24
+ # p arr # => [1, 2, [3, 4]]
25
+ #
26
+ # dup[2][1] = 5 # => [1, 2, [3, 5]]
27
+ # p arr # => [1, 2, [3, 5]]
28
+
29
+ def deep_dup
30
+ self.map {|item| item.deep_dup }
31
+ end
32
+ end
33
+
34
+ class Hash
35
+
36
+ # When called on a hash, the +#deep_dup+ method duplicates all the key-value
37
+ # pairs in the hash recursively, so that actions on the duplicate do not affect
38
+ # the original hash:
39
+ #
40
+ # hash = {a: {b: 2}} # => {a: {b: 2}}
41
+ # dup, deep = hash.dup, hash.deep_dup # => {a: {b: 2}}, {a: {b: 2}}
42
+ #
43
+ # deep[:a][:b] = 14 # => {a: {b: 14}}
44
+ # p hash # => {a: {b: 2}}
45
+ #
46
+ # dup[:a][:b] = 14 # => {a: {b: 14}}
47
+ # p hash # => {a: {b: 14}}
48
+
49
+ def deep_dup
50
+ self.each_with_object(dup) do |(key, value), hash|
51
+ hash[key.deep_dup] = value.deep_dup
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,39 @@
1
+ class Object
2
+
3
+ # The +#duplicable?+ method checks whether an object may be safely duplicated.
4
+ # It returns true, unless the object calling it has its own method called
5
+ # +#duplicable?+. The +#duplicable?+ method is defined for non-duplicable
6
+ # classes in +./object/duplicable.rb+.
7
+
8
+ def duplicable?
9
+ true
10
+ end
11
+ end
12
+
13
+ # Define +#duplicable?+ for all of the classes in the array.
14
+
15
+ [NilClass, FalseClass, TrueClass, Method, Symbol, Numeric].each do |klass|
16
+ klass.class_eval do
17
+ def duplicable?
18
+ false
19
+ end
20
+ end
21
+ end
22
+
23
+ require 'bigdecimal'
24
+
25
+ # BigDecimal class from Ruby's standard library. See documentation for version
26
+ # 2.1.3[http://www.ruby-doc.org/stdlib-2.1.3/libdoc/bigdecimal/rdoc/BigDecimal.html],
27
+ # 2.0.0[http://ruby-doc.org/stdlib-2.0.0/libdoc/bigdecimal/rdoc/BigDecimal.html], or
28
+ # 1.9.3[http://www.ruby-doc.org/stdlib-1.9.3/libdoc/bigdecimal/rdoc/BigDecimal.html].
29
+
30
+ class BigDecimal
31
+
32
+ # This is required for compatibility with Ruby 1.9.x. In Ruby 1.9.x,
33
+ # +dup+ is not allowed on a BigDecimal and raises a TypeError. Rescue
34
+ # the type error to simply return false.
35
+
36
+ def duplicable?
37
+ !!self.dup rescue super
38
+ end
39
+ end