justools 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/CHANGELOG.rdoc +52 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +31 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +135 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/lib/justools.rb +7 -0
- data/lib/justools/core_ext.rb +6 -0
- data/lib/justools/core_ext/array.rb +5 -0
- data/lib/justools/core_ext/array/args_and_opts.rb +41 -0
- data/lib/justools/core_ext/array/filters.rb +7 -0
- data/lib/justools/core_ext/array/flatten_splat.rb +27 -0
- data/lib/justools/core_ext/array/inquiry.rb +42 -0
- data/lib/justools/core_ext/array/merge_options.rb +45 -0
- data/lib/justools/core_ext/class.rb +41 -0
- data/lib/justools/core_ext/enumerable.rb +12 -0
- data/lib/justools/core_ext/hash.rb +9 -0
- data/lib/justools/core_ext/object.rb +92 -0
- data/lib/justools/core_ext/set.rb +7 -0
- data/lib/tasks/core_utilities_tasks.rake +4 -0
- data/spec/justools_spec.rb +8 -0
- data/spec/spec_helper.rb +12 -0
- metadata +151 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
== 1.2.0
|
2
|
+
|
3
|
+
* Re-architecting for Jeweler compatibility
|
4
|
+
* Removing test/ directory in favor of skeletal RSpec setup (coming soon)
|
5
|
+
|
6
|
+
== 1.1.10
|
7
|
+
|
8
|
+
* Ruby 1.9 doesn't need this patch mucking with the internal definition of rotate.
|
9
|
+
|
10
|
+
== 1.1.8
|
11
|
+
|
12
|
+
* Invalid regexp for args_and_opts
|
13
|
+
|
14
|
+
== 1.1.8
|
15
|
+
|
16
|
+
* Defining Object#in? regardless of its pre-existence.
|
17
|
+
|
18
|
+
== 1.1.7
|
19
|
+
|
20
|
+
* Ruby < 1.9 does not have Array#rotate.
|
21
|
+
|
22
|
+
== 1.1.6
|
23
|
+
|
24
|
+
* Renaming from CoreUtilities ('core\_utilities' gem) to Justools.
|
25
|
+
|
26
|
+
* Removing unnecessary dependencies on ActiveSupport, Rails, Significance, Schrodinger's Cat.
|
27
|
+
|
28
|
+
* Not doubly defining methods in extensions if they are already defined.
|
29
|
+
|
30
|
+
* Stunting/disabling 'args and opts' with method missing assistance for Ruby < 1.9.
|
31
|
+
|
32
|
+
* Syntax changes to conform to best practices and style guides.
|
33
|
+
|
34
|
+
* Deactivating class attribute with default extension.
|
35
|
+
|
36
|
+
* Merging extract options with merge options file.
|
37
|
+
|
38
|
+
* Renaming (or aliasing) methods to better fit with RSpec should syntaxes.
|
39
|
+
|
40
|
+
* Slowly deprecating old names by setting up transition via alias method.
|
41
|
+
|
42
|
+
* Adding comment-based documentation with examples and parameters.
|
43
|
+
|
44
|
+
* Updating main README file.
|
45
|
+
|
46
|
+
== 0.1.0
|
47
|
+
|
48
|
+
* Serious effort at making a legit gem.
|
49
|
+
|
50
|
+
== 0.0.1
|
51
|
+
|
52
|
+
* Testing setup
|
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "rspec", "~> 2.11.0"
|
10
|
+
gem "rdoc", "~> 3.12"
|
11
|
+
gem "bundler", ">= 1.0.0"
|
12
|
+
gem "jeweler", "~> 1.8.4"
|
13
|
+
# gem "rcov", ">= 0"
|
14
|
+
# gem 'activesupport', '>= 3.1.0'
|
15
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.3)
|
5
|
+
git (1.2.5)
|
6
|
+
jeweler (1.8.4)
|
7
|
+
bundler (~> 1.0)
|
8
|
+
git (>= 1.2.5)
|
9
|
+
rake
|
10
|
+
rdoc
|
11
|
+
json (1.7.5)
|
12
|
+
rake (0.9.2.2)
|
13
|
+
rdoc (3.12)
|
14
|
+
json (~> 1.4)
|
15
|
+
rspec (2.11.0)
|
16
|
+
rspec-core (~> 2.11.0)
|
17
|
+
rspec-expectations (~> 2.11.0)
|
18
|
+
rspec-mocks (~> 2.11.0)
|
19
|
+
rspec-core (2.11.1)
|
20
|
+
rspec-expectations (2.11.3)
|
21
|
+
diff-lcs (~> 1.1.3)
|
22
|
+
rspec-mocks (2.11.3)
|
23
|
+
|
24
|
+
PLATFORMS
|
25
|
+
ruby
|
26
|
+
|
27
|
+
DEPENDENCIES
|
28
|
+
bundler (>= 1.0.0)
|
29
|
+
jeweler (~> 1.8.4)
|
30
|
+
rdoc (~> 3.12)
|
31
|
+
rspec (~> 2.11.0)
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 caleon.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
= Justools (formerly CoreUtilities)
|
2
|
+
|
3
|
+
Ruby-level extensions, utilities, convenience methods that I've found I'm constantly using in all my projects.
|
4
|
+
|
5
|
+
== Usage:
|
6
|
+
|
7
|
+
gem 'justools', :git => "git://github.com/caleon/justools.git"
|
8
|
+
|
9
|
+
== Selected Examples:
|
10
|
+
|
11
|
+
=== Object
|
12
|
+
|
13
|
+
==== Object#as
|
14
|
+
|
15
|
+
[:donkey, { :class => 'list-item' }].as { |arg, opts| link_to(arg, opts) }
|
16
|
+
|
17
|
+
==== Object#is_included_in? (deprecated by ActiveSupport's newest Object#in?)
|
18
|
+
|
19
|
+
User.find(1).class.is_included_in?(User, Article, Authentication)
|
20
|
+
|
21
|
+
or alternatively:
|
22
|
+
|
23
|
+
@user.is_one_kind_of?(User, Article, Authentication)
|
24
|
+
|
25
|
+
which has the same effect as:
|
26
|
+
|
27
|
+
@user.is_one_kind_of?([User, Article, Authentication])
|
28
|
+
|
29
|
+
by virtue of:
|
30
|
+
|
31
|
+
=== Array
|
32
|
+
|
33
|
+
==== Array#flatten_splat!
|
34
|
+
|
35
|
+
#flatten_splat is for the common pattern of writing a method whose arguments are prepended by the splat operator, like the following:
|
36
|
+
|
37
|
+
def find(*types)
|
38
|
+
types = types.first if types.size == 1 and types.first.is_a?(Array)
|
39
|
+
# ...
|
40
|
+
end
|
41
|
+
|
42
|
+
... which can now be written as:
|
43
|
+
|
44
|
+
def find(*types)
|
45
|
+
types.flatten_splat!
|
46
|
+
end
|
47
|
+
|
48
|
+
==== array/base, array/filters
|
49
|
+
|
50
|
+
These contain further convenience methods, none of them really novel or anything.
|
51
|
+
|
52
|
+
==== Array#extract_options(!)
|
53
|
+
|
54
|
+
Extending the behavior introduced by ActiveSupport, this one goes further to define Array#extract_options as the non-destructive analog, and also introduces Array#extract_options_with_merge. Previously you may have written:
|
55
|
+
|
56
|
+
def find(*args)
|
57
|
+
opts = args.extract_options!
|
58
|
+
opts[:user_id] = self.article.user_id
|
59
|
+
opts[:found_at] = Time.now
|
60
|
+
end
|
61
|
+
|
62
|
+
but now you can write:
|
63
|
+
|
64
|
+
def find(*args)
|
65
|
+
opts = args.extract_options_with_merge(:user_id => self.article.user_id, :found_at => Time.now)
|
66
|
+
end
|
67
|
+
|
68
|
+
Note: The inclusion of this gem makes the *_with_merge methods the default behavior for extract_options(!) via alias_method_chain.
|
69
|
+
|
70
|
+
==== Array#merge_options(!)
|
71
|
+
|
72
|
+
If you find yourself extracting options as above only to re-inject that hash back into the original array to pass the arguments to a helper method (after some merging of the options hash), you may consider utilizing #merge_options:
|
73
|
+
|
74
|
+
def find(*args)
|
75
|
+
find_helper(*args.merge_options(:user_id => self.article.user_id, :found_at => Time.now))
|
76
|
+
end
|
77
|
+
|
78
|
+
==== Array #arguments_and_options (a.k.a. #args_and_opts)
|
79
|
+
|
80
|
+
The above Array methods lead to this handy method whose utility, in essence, is in its shortening a common Ruby pattern into a single line. Previously you may have written:
|
81
|
+
|
82
|
+
def find(*arguments)
|
83
|
+
mandatory_opts = { :user_id => self.article.user_id, :found_at => Time.now }
|
84
|
+
|
85
|
+
opts = arguments.extract_options!
|
86
|
+
an_id = arguments.shift
|
87
|
+
|
88
|
+
opts.merge!(mandatory_opts)
|
89
|
+
end
|
90
|
+
|
91
|
+
which, with the help of #args_and_opts (and the help of of #method_missing for extending its functionality) you can write:
|
92
|
+
|
93
|
+
def find(*arguments)
|
94
|
+
an_id, opts = arguments.args_with_shift_and_opts_with_merge!(:user_id => self.article.user_id, :found_at => Time.now)
|
95
|
+
end
|
96
|
+
|
97
|
+
==== Note
|
98
|
+
|
99
|
+
The method_missing hook to allow the above functionality (explained in more detail below) is only available for Ruby 1.9+ because it depends, to an extent, on the availability of the method Method#parameters.
|
100
|
+
|
101
|
+
Basically the format of the method call is arg(ument)?s(\_with\_[ARGMETHOD])?\_and_opt(ion)?s(\_with\_[OPTSMETHOD])?!, where the ARGMETHOD is the name of the method which applies to the "args" part of the array, and OPTSMETHOD would be the name of the method which is called on the "opts" part of the array.
|
102
|
+
|
103
|
+
Additionally, arguments can be passed to #args_and_opts, but as of now, in the event that both ARGMETHOD and OPTSMETHOD are defined, the arguments will be passed to the OPTSMETHOD only. Some effort was made to utilize arity to determine where the arguments should be passed to, but to my recollection this is still an unfinished aspect.
|
104
|
+
|
105
|
+
|
106
|
+
=== Enumerable
|
107
|
+
|
108
|
+
Has #map_select and #map_detect.
|
109
|
+
|
110
|
+
=== Set
|
111
|
+
|
112
|
+
Has #not_subset?(set)
|
113
|
+
|
114
|
+
=== Hash
|
115
|
+
|
116
|
+
Has #append_value which is similar to merging hashes, but in cases where you don't want to override the value of one of the hashes and would rather JOIN the values corresponding to the same key, (for example, wanting to add class names in a DOM element in Rails rather than overriding the original { :class => 'className' } hash):
|
117
|
+
|
118
|
+
{ :id => "user_1-comments", :class => "user-comments" }.append_value!(:class, 'comments')
|
119
|
+
# => { :id => "user_1-comments", :class => "user-comments comments" }
|
120
|
+
|
121
|
+
== Additional information
|
122
|
+
|
123
|
+
=== Contributors
|
124
|
+
|
125
|
+
Please feel free to contact me about collaborating on this project.
|
126
|
+
|
127
|
+
http://github.com/caleon/justools/contributors
|
128
|
+
|
129
|
+
=== Maintainers
|
130
|
+
|
131
|
+
* caleon (http://github.com/caleon)
|
132
|
+
|
133
|
+
== License
|
134
|
+
|
135
|
+
MIT License. Copyright 2012 caleon.
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "justools"
|
18
|
+
gem.homepage = "http://github.com/caleon/justools"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Core extensions with lots of handy methods}
|
21
|
+
gem.description = %Q{Core extensions with lots of handy methods}
|
22
|
+
gem.email = "caleon@gmail.com"
|
23
|
+
gem.authors = ["caleon"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
31
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
35
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
36
|
+
spec.rcov = true
|
37
|
+
end
|
38
|
+
|
39
|
+
task :default => :spec
|
40
|
+
|
41
|
+
require 'rdoc/task'
|
42
|
+
Rake::RDocTask.new do |rdoc|
|
43
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
44
|
+
|
45
|
+
rdoc.rdoc_dir = 'rdoc'
|
46
|
+
rdoc.title = "Justools #{version}"
|
47
|
+
rdoc.rdoc_files.include('README*')
|
48
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
49
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.2.0
|
data/lib/justools.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'justools/core_ext/array/merge_options'
|
2
|
+
|
3
|
+
class Array
|
4
|
+
unless Array.instance_methods.include?(:rotate) # Was only patch for 1.8
|
5
|
+
def rotate
|
6
|
+
self[0..-2].unshift(self[-1])
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def arguments_and_options(update_hash = {})
|
11
|
+
merge_options(update_hash).args_and_opts!
|
12
|
+
end
|
13
|
+
|
14
|
+
def arguments_and_options!(update_hash = {})
|
15
|
+
[extract_options_with_merge!(update_hash), self].rotate
|
16
|
+
end
|
17
|
+
|
18
|
+
[:args_and_opts!, :args_and_opts_with_merge!,
|
19
|
+
:arguments_and_options_with_merge!].each do |meth|
|
20
|
+
alias_method meth, :arguments_and_options!
|
21
|
+
alias_method meth.to_s[0..-2].to_sym, :arguments_and_options
|
22
|
+
end
|
23
|
+
|
24
|
+
# Method#parameters only available in Ruby 1.9+
|
25
|
+
if RUBY_VERSION > '1.9'
|
26
|
+
private
|
27
|
+
def method_missing(method_symbol, *args, &block)
|
28
|
+
return super unless method_symbol =~ Justools::ARGS_AND_OPTS_REGEXP
|
29
|
+
|
30
|
+
[$1, $2].zip(args_and_opts).map do |m, obj|
|
31
|
+
next if m.respond_to?(:empty?) ? empty? : !m
|
32
|
+
obj.send(m.to_sym, *args.send(:constrained_by_method, obj.method(m.to_sym)))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def constrained_by_method(methud)
|
37
|
+
methud.parameters.detect { |t, _| t == :rest } or return self
|
38
|
+
take([methud.parameters.size, methud.arity.abs].max)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
class Array
|
2
|
+
# Quick selectors/filters
|
3
|
+
def select_kind_of(klass); select { |el| el.kind_of?(klass) }; end
|
4
|
+
def reject_kind_of(klass); reject { |el| el.kind_of?(klass) }; end
|
5
|
+
def select_kind_of!(klass); select! { |el| el.kind_of?(klass) }; end
|
6
|
+
def reject_kind_of!(klass); reject! { |el| el.kind_of?(klass) }; end
|
7
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Array
|
2
|
+
# flatten_splat! is used for dealing conveniently with the common pattern
|
3
|
+
# where a method's arguments has a splat (*) operator, but the developer wants
|
4
|
+
# to provide the option of the method accepting either a list or an array for
|
5
|
+
# the argument.
|
6
|
+
#
|
7
|
+
# === Examples
|
8
|
+
#
|
9
|
+
# Before: Now:
|
10
|
+
# def do_something(*args) def do_something(*args)
|
11
|
+
# if args.one? && args[0].is_a?(Array) args.flatten_splat!
|
12
|
+
# args = args.shift end
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
def flatten_splat!
|
16
|
+
flatten_splat(true)
|
17
|
+
end
|
18
|
+
|
19
|
+
def flatten_splat(with_bang=false)
|
20
|
+
flatten_splat_needed? ? with_bang ? flatten! : flatten : self
|
21
|
+
end
|
22
|
+
|
23
|
+
def flatten_splat_needed?
|
24
|
+
self.size == 1 and first.is_a?(Array)
|
25
|
+
end
|
26
|
+
private :flatten_splat_needed?
|
27
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'justools/core_ext/object'
|
3
|
+
require 'justools/core_ext/set'
|
4
|
+
require 'justools/core_ext/array/flatten_splat'
|
5
|
+
|
6
|
+
class Array
|
7
|
+
# Compares two arrays to see if the elements are same but simply rearranged.
|
8
|
+
#
|
9
|
+
# === Parameters
|
10
|
+
#
|
11
|
+
# * +other_ary+ - An Array or a list of its elements.
|
12
|
+
def rearranged?(*other_ary)
|
13
|
+
Set.new(self) == Set.new(other_ary.flatten_splat)
|
14
|
+
end
|
15
|
+
alias_method :rearranges?, :rearranged?
|
16
|
+
|
17
|
+
def subset_of?(other_ary)
|
18
|
+
Set.new(self).subset?(Set.new(other_ary))
|
19
|
+
end
|
20
|
+
alias_method :subset?, :subset_of?
|
21
|
+
|
22
|
+
def is_included_in?(other_ary)
|
23
|
+
super || subset?(other_ary)
|
24
|
+
end
|
25
|
+
alias_method :in?, :is_included_in?
|
26
|
+
|
27
|
+
# Careful with this. This means 4 out of 5 elements can be the same but if not
|
28
|
+
# all of this self Array object are a part of other_ary, this returns true, as
|
29
|
+
# in "Yes, depite having 4 out of 5 in other_ary, I am excluded from the
|
30
|
+
# other_ary."
|
31
|
+
def out_of?(other_ary)
|
32
|
+
super || not_subset?(other_ary)
|
33
|
+
end
|
34
|
+
alias_method :is_excluded_from?, :out_of?
|
35
|
+
|
36
|
+
alias_method :include_one?, :include?
|
37
|
+
def include_all?(*other_ary)
|
38
|
+
other_ary.flatten_splat!
|
39
|
+
include_one(other_ary) || superset?(other_ary)
|
40
|
+
end
|
41
|
+
# alias_method :include?, :include_all?
|
42
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
unless Hash.method_defined?(:extractable_options?)
|
2
|
+
class Hash
|
3
|
+
# Duplicated from ActiveSupport
|
4
|
+
def extractable_options?
|
5
|
+
instance_of?(Hash)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class Array
|
11
|
+
def extract_options_without_merge
|
12
|
+
options_extractable? ? last : {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def extract_options_without_merge!
|
16
|
+
options_extractable? ? pop : {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def options_extractable?
|
20
|
+
last.is_a?(Hash) && last.extractable_options?
|
21
|
+
end
|
22
|
+
|
23
|
+
def extract_options_with_merge(update_hash = {})
|
24
|
+
extract_options_without_merge.merge(update_hash || {})
|
25
|
+
end
|
26
|
+
alias_method :extract_options, :extract_options_with_merge
|
27
|
+
|
28
|
+
def extract_options_with_merge!(update_hash = {})
|
29
|
+
extract_options_without_merge!.merge(update_hash || {})
|
30
|
+
end
|
31
|
+
alias_method :extract_options!, :extract_options_with_merge!
|
32
|
+
|
33
|
+
##
|
34
|
+
# == Merging options
|
35
|
+
def merge_options(update_hash = {})
|
36
|
+
endex, base_hash = options_extractable? ? [-2, last] : [-1, {}]
|
37
|
+
self[0..endex] + Array[base_hash.merge(update_hash || {})]
|
38
|
+
end
|
39
|
+
alias_method :merge_opts, :merge_options
|
40
|
+
|
41
|
+
def merge_options!(update_hash = {})
|
42
|
+
push(extract_options!(update_hash))
|
43
|
+
end
|
44
|
+
alias_method :merge_opts!, :merge_options!
|
45
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# Not enabling until fixed.
|
2
|
+
require 'active_support/core_ext/class/attribute'
|
3
|
+
require 'active_support/core_ext/module/aliasing'
|
4
|
+
|
5
|
+
class Class
|
6
|
+
# Purpose is to be able to define a default value for a class_attribute when
|
7
|
+
# one isn't initially set.
|
8
|
+
def class_attribute_with_default(*attrs)
|
9
|
+
hash = attrs.last.is_a?(Hash) ? attrs.pop : {}
|
10
|
+
my_default = hash.delete(:default)
|
11
|
+
instance_writer = hash.blank? || hash[:instance_writer]
|
12
|
+
|
13
|
+
attrs.each do |name|
|
14
|
+
# By the way, FIXME: i think this should be broken because if i want to
|
15
|
+
# use a string as a default, that will not be reflected.
|
16
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
17
|
+
def self.#{name}() #{my_default || 'nil'} end
|
18
|
+
def self.#{name}?() !!#{name} end
|
19
|
+
|
20
|
+
def self.#{name}=(val)
|
21
|
+
singleton_class.class_eval do
|
22
|
+
remove_possible_method(:#{name})
|
23
|
+
define_method(:#{name}) { val }
|
24
|
+
end
|
25
|
+
val
|
26
|
+
end
|
27
|
+
|
28
|
+
def #{name}
|
29
|
+
defined?(@#{name}) ? @#{name} : singleton_class.#{name}
|
30
|
+
end
|
31
|
+
|
32
|
+
def #{name}?
|
33
|
+
!!#{name}
|
34
|
+
end
|
35
|
+
RUBY
|
36
|
+
|
37
|
+
attr_writer name if instance_writer
|
38
|
+
end
|
39
|
+
end
|
40
|
+
alias_method_chain :class_attribute, :default
|
41
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Enumerable
|
2
|
+
def map_select(value_for_skip = nil)
|
3
|
+
self.inject([]) do |acc, item|
|
4
|
+
(value = yield(item)) == value_for_skip ? acc : acc << value
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
def map_detect(value_for_no_matching = nil)
|
9
|
+
self.each { |el| if result = yield(el) then return result end }
|
10
|
+
value_for_no_matching
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'justools/core_ext/array/flatten_splat'
|
2
|
+
|
3
|
+
class Object
|
4
|
+
|
5
|
+
# === Examples
|
6
|
+
#
|
7
|
+
# { :a=>1, .., :z=>26 }.as { |h| h.each { |k, v| h[k] = v + h[26 - v] } }
|
8
|
+
#
|
9
|
+
# User.find(15).stories.joins(:tasks).as { |s| [s.class.to_s, s.count] }.
|
10
|
+
# as { |klass_name, count| "#{count} stories in #{klass_name}" }
|
11
|
+
#
|
12
|
+
# [15, { :includes => { :stories => :tasks } }, 56, 78, 102].
|
13
|
+
# as { |id, opts, *ns| ns.each { |n| puts n }; User.find(id, opts) }
|
14
|
+
def as(&block)
|
15
|
+
yield self
|
16
|
+
end
|
17
|
+
|
18
|
+
# === Examples
|
19
|
+
#
|
20
|
+
# user = User.find_by_id(10).or_else { |res| raise "Got back #{res}" }
|
21
|
+
def or_else(&block)
|
22
|
+
self || yield(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
# === Examples
|
26
|
+
#
|
27
|
+
# authorization = User.find_by_id(10).and_also { |u| u.authorization }
|
28
|
+
def and_also(&block)
|
29
|
+
self && yield(self)
|
30
|
+
end
|
31
|
+
|
32
|
+
# unless Object.method_defined?(:in?)
|
33
|
+
# Copy of Object#in? from Rails 3.2.1 which also allows list.
|
34
|
+
#
|
35
|
+
# === Parameters
|
36
|
+
#
|
37
|
+
# * +args+ - Array or a list of its contents.
|
38
|
+
def in?(*args)
|
39
|
+
if args.length > 1
|
40
|
+
args.include? self
|
41
|
+
else
|
42
|
+
another_object = args.first
|
43
|
+
if another_object.respond_to? :include?
|
44
|
+
another_object.include?(self)
|
45
|
+
else
|
46
|
+
raise ArgumentError.new("The single parameter passed to #in? must respond to #include?")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
# end
|
51
|
+
# def is_included_in?(*others) #d deprecated
|
52
|
+
# others.flatten_splat.include?(self)
|
53
|
+
# end
|
54
|
+
alias_method :is_included_in?, :in?
|
55
|
+
|
56
|
+
def out_of?(*others)
|
57
|
+
others.flatten_splat.exclude?(self)
|
58
|
+
end
|
59
|
+
alias_method :is_excluded_from?, :out_of?
|
60
|
+
|
61
|
+
# Similar to is_a? or kind_of? but with an array of possible classes.
|
62
|
+
# Returns the matching class or a nil.
|
63
|
+
#
|
64
|
+
# === Parameters
|
65
|
+
#
|
66
|
+
# * +klasses+ - List of Class constants, or an Array of Class constants.
|
67
|
+
#
|
68
|
+
# === Examples
|
69
|
+
#
|
70
|
+
# rec_or_num.one_kind_of?(User, Admin).or_else { User.find(rec_or_num) }
|
71
|
+
def one_kind_of?(*klasses)
|
72
|
+
klasses.flatten_splat.detect { |klass| self.kind_of?(klass) }
|
73
|
+
end
|
74
|
+
alias_method :is_one_kind_of?, :one_kind_of?
|
75
|
+
|
76
|
+
# Similar to is_a? or kind_of? but with an array of possible classes.
|
77
|
+
# Returns the matching class or a nil. Renamed here from is_one_kind_of?
|
78
|
+
# because it uses the 'klass === self' which isn't necessarily equivalent to
|
79
|
+
# 'self.is_a?(klass)'.
|
80
|
+
#
|
81
|
+
# === Parameters
|
82
|
+
#
|
83
|
+
# * +args+ - List of arguments.
|
84
|
+
#
|
85
|
+
# === Examples
|
86
|
+
#
|
87
|
+
# rec_or_num.one_of?(User, Admin).or_else { User.find(rec_or_num) }
|
88
|
+
def one_of?(*args)
|
89
|
+
args.flatten_splat.detect { |arg| arg === self}
|
90
|
+
end
|
91
|
+
alias_method :is_when?, :one_of?
|
92
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
require 'justools'
|
5
|
+
|
6
|
+
# Requires supporting files with custom matchers and macros, etc,
|
7
|
+
# in ./support/ and its subdirectories.
|
8
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.alias_it_should_behave_like_to :it_has_behavior, 'has behavior:'
|
12
|
+
end
|
metadata
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: justools
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 31
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 1.2.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- caleon
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-10-23 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
hash: 35
|
28
|
+
segments:
|
29
|
+
- 2
|
30
|
+
- 11
|
31
|
+
- 0
|
32
|
+
version: 2.11.0
|
33
|
+
type: :development
|
34
|
+
name: rspec
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 31
|
44
|
+
segments:
|
45
|
+
- 3
|
46
|
+
- 12
|
47
|
+
version: "3.12"
|
48
|
+
type: :development
|
49
|
+
name: rdoc
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
prerelease: false
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 23
|
59
|
+
segments:
|
60
|
+
- 1
|
61
|
+
- 0
|
62
|
+
- 0
|
63
|
+
version: 1.0.0
|
64
|
+
type: :development
|
65
|
+
name: bundler
|
66
|
+
version_requirements: *id003
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
prerelease: false
|
69
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ~>
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
hash: 63
|
75
|
+
segments:
|
76
|
+
- 1
|
77
|
+
- 8
|
78
|
+
- 4
|
79
|
+
version: 1.8.4
|
80
|
+
type: :development
|
81
|
+
name: jeweler
|
82
|
+
version_requirements: *id004
|
83
|
+
description: Core extensions with lots of handy methods
|
84
|
+
email: caleon@gmail.com
|
85
|
+
executables: []
|
86
|
+
|
87
|
+
extensions: []
|
88
|
+
|
89
|
+
extra_rdoc_files:
|
90
|
+
- README.rdoc
|
91
|
+
files:
|
92
|
+
- .document
|
93
|
+
- .rspec
|
94
|
+
- CHANGELOG.rdoc
|
95
|
+
- Gemfile
|
96
|
+
- Gemfile.lock
|
97
|
+
- MIT-LICENSE
|
98
|
+
- README.rdoc
|
99
|
+
- Rakefile
|
100
|
+
- VERSION
|
101
|
+
- lib/justools.rb
|
102
|
+
- lib/justools/core_ext.rb
|
103
|
+
- lib/justools/core_ext/array.rb
|
104
|
+
- lib/justools/core_ext/array/args_and_opts.rb
|
105
|
+
- lib/justools/core_ext/array/filters.rb
|
106
|
+
- lib/justools/core_ext/array/flatten_splat.rb
|
107
|
+
- lib/justools/core_ext/array/inquiry.rb
|
108
|
+
- lib/justools/core_ext/array/merge_options.rb
|
109
|
+
- lib/justools/core_ext/class.rb
|
110
|
+
- lib/justools/core_ext/enumerable.rb
|
111
|
+
- lib/justools/core_ext/hash.rb
|
112
|
+
- lib/justools/core_ext/object.rb
|
113
|
+
- lib/justools/core_ext/set.rb
|
114
|
+
- lib/tasks/core_utilities_tasks.rake
|
115
|
+
- spec/justools_spec.rb
|
116
|
+
- spec/spec_helper.rb
|
117
|
+
homepage: http://github.com/caleon/justools
|
118
|
+
licenses:
|
119
|
+
- MIT
|
120
|
+
post_install_message:
|
121
|
+
rdoc_options: []
|
122
|
+
|
123
|
+
require_paths:
|
124
|
+
- lib
|
125
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
126
|
+
none: false
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
hash: 3
|
131
|
+
segments:
|
132
|
+
- 0
|
133
|
+
version: "0"
|
134
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
|
+
none: false
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
hash: 3
|
140
|
+
segments:
|
141
|
+
- 0
|
142
|
+
version: "0"
|
143
|
+
requirements: []
|
144
|
+
|
145
|
+
rubyforge_project:
|
146
|
+
rubygems_version: 1.8.24
|
147
|
+
signing_key:
|
148
|
+
specification_version: 3
|
149
|
+
summary: Core extensions with lots of handy methods
|
150
|
+
test_files: []
|
151
|
+
|