finishing_moves 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +34 -0
- data/.rspec +3 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +58 -0
- data/LICENSE +22 -0
- data/README.md +602 -0
- data/Vagrantfile +44 -0
- data/finishing_moves.gemspec +31 -0
- data/lib/finishing_moves.rb +7 -0
- data/lib/finishing_moves/fixnum.rb +23 -0
- data/lib/finishing_moves/hash.rb +27 -0
- data/lib/finishing_moves/object.rb +42 -0
- data/lib/finishing_moves/to_bool.rb +33 -0
- data/lib/finishing_moves/version.rb +3 -0
- data/provision.sh +71 -0
- data/spec/fixnum_spec.rb +35 -0
- data/spec/hash_spec.rb +30 -0
- data/spec/object_spec.rb +105 -0
- data/spec/spec_helper.rb +99 -0
- data/spec/to_bool_spec.rb +69 -0
- metadata +144 -0
data/Vagrantfile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
NAME = "finishing-moves"
|
5
|
+
FQDN = "#{NAME}.example.com"
|
6
|
+
|
7
|
+
Vagrant.configure("2") do |config|
|
8
|
+
# "trusty" is 14.04
|
9
|
+
config.vm.box = "trusty32"
|
10
|
+
config.vm.box_url = "https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-i386-vagrant-disk1.box"
|
11
|
+
|
12
|
+
config.vm.provider :virtualbox do |vb|
|
13
|
+
vb.customize ["modifyvm", :id,
|
14
|
+
# Basics.
|
15
|
+
"--name", NAME,
|
16
|
+
"--memory", 4096,
|
17
|
+
# I/O APIC must be enabled to support a multi-core guest.
|
18
|
+
"--cpus", 4,
|
19
|
+
"--ioapic", "on",
|
20
|
+
# Enable native host virtualization features (yields better performance).
|
21
|
+
"--pae", "on",
|
22
|
+
"--hwvirtex", "on",
|
23
|
+
"--largepages", "on",
|
24
|
+
"--vtxvpid", "on",
|
25
|
+
# This causes the virtual machine to proxy DNS requests through the host
|
26
|
+
# via NAT. Without this, the default resolver on the guest will introduce
|
27
|
+
# a 5 second latency on every HTTP request... which is a real downer.
|
28
|
+
"--natdnshostresolver1", "on"
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
config.vm.hostname = FQDN
|
33
|
+
config.vm.provision :shell, path: "provision.sh"
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# DONT FORGET!
|
38
|
+
#
|
39
|
+
# Force update VirtualBox Guest Additions
|
40
|
+
# Run the following command inside same directory as Vagrantfile
|
41
|
+
# Must be done once on your dev system
|
42
|
+
#
|
43
|
+
# vagrant plugin install vagrant-vbguest
|
44
|
+
#
|
@@ -0,0 +1,31 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
|
3
|
+
require "finishing_moves/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
|
7
|
+
s.name = "finishing_moves"
|
8
|
+
s.version = FinishingMoves::VERSION
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.authors = ["Frank Koehl", "Chris Tonkinson"]
|
11
|
+
s.email = ["frank@forgecrafted.com", "chris@forgecrafted.com"]
|
12
|
+
s.summary = %q{Small, focused, incredibly useful methods added to core Ruby classes.}
|
13
|
+
s.description = <<-EOF
|
14
|
+
Ruby includes a huge amount of default awesomeness that tackles most common development challenges. But every now and then, you find yourself in a situation where an elaborate-yet-precise coding maneuver wins the day. Finishing Moves is a collection of methods designed to assist in those just-typical-enough-to-be-annoying scenarios.
|
15
|
+
|
16
|
+
In gamer terms, if standard Ruby methods are your default actions, finishing_moves would be mana-consuming techniques. Your cooldown spells. Your grenades (there's never enough grenades). In the right situation, they kick serious cyclomatic butt.
|
17
|
+
EOF
|
18
|
+
s.homepage = "https://github.com/forgecrafted/finishing_moves"
|
19
|
+
s.license = "MIT"
|
20
|
+
|
21
|
+
s.files = `git ls-files -z`.split("\x0")
|
22
|
+
s.test_files = Dir["spec/**/*"]
|
23
|
+
|
24
|
+
s.add_development_dependency 'rb-readline', '>= 0'
|
25
|
+
s.add_development_dependency 'rspec', '~> 3.1.0'
|
26
|
+
s.add_development_dependency 'priscilla', '>= 0'
|
27
|
+
s.add_development_dependency 'pry-byebug', '>= 0'
|
28
|
+
s.add_development_dependency 'fuubar', '>= 0'
|
29
|
+
|
30
|
+
s.required_ruby_version = '>= 2.0'
|
31
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Fixnum
|
2
|
+
def length
|
3
|
+
Math.log10(self.abs).to_i + 1
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
class Bignum
|
8
|
+
def length
|
9
|
+
Math.log10(self.abs).to_i + 1
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Float
|
14
|
+
def length
|
15
|
+
raise ArgumentError.new("Cannot get length: \"#{self}\" is not an integer")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class BigDecimal
|
20
|
+
def length
|
21
|
+
raise ArgumentError.new("Cannot get length: \"#{self}\" is not an integer")
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
# When deleting a value from a hash, return the remaining hash, instead of the deleted value
|
4
|
+
def delete!(key)
|
5
|
+
self.delete(key)
|
6
|
+
return self
|
7
|
+
end
|
8
|
+
|
9
|
+
# Delete all records according to the keys passed in as an array, and return a hash of deleted
|
10
|
+
# entries. Silently ignores any keys which are not found.
|
11
|
+
def delete_each(*hash_keys)
|
12
|
+
deleted_entries = {}
|
13
|
+
hash_keys.each do |hash_key|
|
14
|
+
value = self.delete(hash_key)
|
15
|
+
deleted_entries[hash_key] = value unless value.nil?
|
16
|
+
end
|
17
|
+
return deleted_entries unless deleted_entries.empty?
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
# Delete all records according to the keys passed in as array, and return the remaining hash.
|
22
|
+
def delete_each!(*keys)
|
23
|
+
self.delete_each(*keys)
|
24
|
+
return self
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class Object
|
2
|
+
|
3
|
+
def nil_chain(ret_val = nil, &block)
|
4
|
+
begin
|
5
|
+
result = yield
|
6
|
+
return ret_val if result.nil?
|
7
|
+
result
|
8
|
+
rescue NoMethodError
|
9
|
+
rescue NameError
|
10
|
+
return ret_val
|
11
|
+
end
|
12
|
+
end
|
13
|
+
alias_method :chain, :nil_chain
|
14
|
+
alias_method :method_chain, :nil_chain
|
15
|
+
|
16
|
+
def bool_chain(&block)
|
17
|
+
result = nil_chain(&block)
|
18
|
+
return false if result.nil?
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
22
|
+
def class_exists?(class_name)
|
23
|
+
klass = Module.const_get(class_name.to_s)
|
24
|
+
return klass.is_a?(Class)
|
25
|
+
rescue NameError
|
26
|
+
return false
|
27
|
+
end
|
28
|
+
|
29
|
+
def not_nil?
|
30
|
+
!self.nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
def same_as(compare)
|
34
|
+
if compare.respond_to? :to_s
|
35
|
+
self.to_s == compare.to_s
|
36
|
+
else
|
37
|
+
raise ArgumentError.new("Cannot compare \"#{self.class.name}\" to \"#{compare.class.name}\", no string conversion")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class String
|
2
|
+
def to_bool
|
3
|
+
return true if self == true || self =~ (/^(1|t(rue)?|y(es)?|on)$/i)
|
4
|
+
return false if self == false || self == "" || self =~ /\A[[:space:]]*\z/ || self =~ (/^(0|f(alse)?|no?|off)$/i)
|
5
|
+
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class Fixnum
|
10
|
+
def to_bool
|
11
|
+
return true if self == 1
|
12
|
+
return false if self == 0
|
13
|
+
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class TrueClass
|
18
|
+
def to_bool; self; end
|
19
|
+
def to_i; 1; end
|
20
|
+
def to_sym; :true; end
|
21
|
+
end
|
22
|
+
|
23
|
+
class FalseClass
|
24
|
+
def to_bool; self; end
|
25
|
+
def to_i; 0; end
|
26
|
+
def to_sym; :false; end
|
27
|
+
end
|
28
|
+
|
29
|
+
class NilClass
|
30
|
+
def to_bool; false; end
|
31
|
+
def to_i; 0; end
|
32
|
+
def to_sym; :nil; end
|
33
|
+
end
|
data/provision.sh
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# Shell user settings.
|
4
|
+
USER_NAME=vagrant
|
5
|
+
USER_HOME=/home/$USER_NAME
|
6
|
+
DEFAULT_RUBY='2.1.5'
|
7
|
+
|
8
|
+
###############################################################################
|
9
|
+
# Functions
|
10
|
+
###############################################################################
|
11
|
+
# Most of the time we can get by with this DRY wrapper for sudo commands.
|
12
|
+
as_user() {
|
13
|
+
echo "$USER_NAME:~$ > ${*}"
|
14
|
+
su -l $USER_NAME -c "$*"
|
15
|
+
}
|
16
|
+
|
17
|
+
# Install the requested version of Ruby, with Bundler.
|
18
|
+
install_ruby() {
|
19
|
+
as_user "rbenv install -s $1"
|
20
|
+
as_user "RBENV_VERSION=$1 gem install bundler"
|
21
|
+
as_user "rbenv rehash"
|
22
|
+
}
|
23
|
+
|
24
|
+
###############################################################################
|
25
|
+
# Base System
|
26
|
+
###############################################################################
|
27
|
+
apt-get -y update
|
28
|
+
apt-get -yfV dist-upgrade
|
29
|
+
|
30
|
+
###############################################################################
|
31
|
+
# rbenv & ruby-build, and Rubies
|
32
|
+
# From https://github.com/sstephenson/rbenv
|
33
|
+
# and https://github.com/sstephenson/ruby-build
|
34
|
+
###############################################################################
|
35
|
+
|
36
|
+
# Install dependencies.
|
37
|
+
apt-get install -yfV \
|
38
|
+
build-essential \
|
39
|
+
curl \
|
40
|
+
git-core \
|
41
|
+
libcurl4-openssl-dev \
|
42
|
+
libreadline-dev \
|
43
|
+
libsqlite3-dev \
|
44
|
+
libssl-dev \
|
45
|
+
libxml2-dev \
|
46
|
+
libxslt1-dev \
|
47
|
+
libyaml-dev \
|
48
|
+
python-software-properties \
|
49
|
+
sqlite3 \
|
50
|
+
wget \
|
51
|
+
zlib1g-dev \
|
52
|
+
|
53
|
+
# Install rbenv and ruby-build.
|
54
|
+
as_user "git clone https://github.com/sstephenson/rbenv.git $USER_HOME/.rbenv"
|
55
|
+
as_user "git clone https://github.com/sstephenson/ruby-build.git $USER_HOME/.rbenv/plugins/ruby-build"
|
56
|
+
|
57
|
+
# Setup bash to use rbenv for $USER_NAME.
|
58
|
+
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> $USER_HOME/.bashrc
|
59
|
+
echo 'eval "$(rbenv init -)"' >> $USER_HOME/.bashrc
|
60
|
+
echo 'cd /vagrant' >> $USER_HOME/.bashrc
|
61
|
+
echo 'gem: --no-document' >> $USER_HOME/.gemrc
|
62
|
+
|
63
|
+
# Install Ruby for $USER_NAME.
|
64
|
+
install_ruby $DEFAULT_RUBY
|
65
|
+
echo $DEFAULT_RUBY > $USER_HOME/.ruby-version
|
66
|
+
|
67
|
+
###############################################################################
|
68
|
+
# EDIT HERE!
|
69
|
+
# Install any Rubies (other than $DEFAULT_RUBY) required for individual apps.
|
70
|
+
###############################################################################
|
71
|
+
# e.g. `install_ruby 2.1.4`
|
data/spec/fixnum_spec.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Count number length" do
|
4
|
+
|
5
|
+
it "Fixnum#length" do
|
6
|
+
expect(1.length).to eq 1
|
7
|
+
expect(5.length).to eq 1
|
8
|
+
expect(9.length).to eq 1
|
9
|
+
expect(90.length).to eq 2
|
10
|
+
expect(900.length).to eq 3
|
11
|
+
expect(9000.length).to eq 4
|
12
|
+
expect(-9000.length).to eq 4
|
13
|
+
end
|
14
|
+
|
15
|
+
it "Bignum#length" do
|
16
|
+
expect(12356469787881584554556.length).to eq 23
|
17
|
+
expect(-12356469787881584554556.length).to eq 23
|
18
|
+
end
|
19
|
+
|
20
|
+
it "Float#length" do
|
21
|
+
expect{ 0.0.length }.to raise_error(ArgumentError)
|
22
|
+
expect{ 1.0.length }.to raise_error(ArgumentError)
|
23
|
+
expect{ -1.0.length }.to raise_error(ArgumentError)
|
24
|
+
expect{ 3.14.length }.to raise_error(ArgumentError)
|
25
|
+
expect{ 12356469.987.length }.to raise_error(ArgumentError)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "BigDecimal#length" do
|
29
|
+
expect{ 1265437718438866624512.123.length }.to raise_error(ArgumentError)
|
30
|
+
expect{ -1265437718438866624512.123.length }.to raise_error(ArgumentError)
|
31
|
+
expect{ 0.9999999999999062.length }.to raise_error(ArgumentError)
|
32
|
+
expect{ -0.9999999999999062.length }.to raise_error(ArgumentError)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/spec/hash_spec.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hash do
|
4
|
+
|
5
|
+
let :test_hash do
|
6
|
+
{ :foo => :bar, :baz => :bin, :flo => :bie }
|
7
|
+
end
|
8
|
+
|
9
|
+
it "#delete!" do
|
10
|
+
expect(test_hash.delete!(:bogus)).to eq({ :foo => :bar, :baz => :bin, :flo => :bie })
|
11
|
+
expect(test_hash.delete!(:baz)).to eq({ :foo => :bar, :flo => :bie })
|
12
|
+
end
|
13
|
+
|
14
|
+
it "#delete_each" do
|
15
|
+
expect(test_hash.delete_each(:bogus, :bar)).to eq nil
|
16
|
+
expect(test_hash).to eq({ :foo => :bar, :baz => :bin, :flo => :bie })
|
17
|
+
expect(test_hash.delete_each(:flo)).to eq({ :flo => :bie })
|
18
|
+
expect(test_hash).to eq({ :foo => :bar, :baz => :bin })
|
19
|
+
expect(test_hash.delete_each(:foo, :baz, :bogus)).to eq({ :foo => :bar, :baz => :bin })
|
20
|
+
expect(test_hash).to eq({ })
|
21
|
+
end
|
22
|
+
|
23
|
+
it "#delete_each!" do
|
24
|
+
expect(test_hash.delete_each!(:bogus, :bar)).to eq({ :foo => :bar, :baz => :bin, :flo => :bie })
|
25
|
+
expect(test_hash.delete_each!(:flo)).to eq({ :foo => :bar, :baz => :bin })
|
26
|
+
expect(test_hash.delete_each!(:bogus, :flo, :foo)).to eq({ :baz => :bin })
|
27
|
+
expect(test_hash.delete_each!(:baz)).to eq({ })
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/spec/object_spec.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Object do
|
4
|
+
|
5
|
+
it "#nil_chain" do
|
6
|
+
expect(nil_chain{bogus_variable}).to eq nil
|
7
|
+
expect(nil_chain{bogus_hash[:foo]}).to eq nil
|
8
|
+
params = { :foo => 'bar' }
|
9
|
+
expect(nil_chain{ params[:bogus_key] }).to eq nil
|
10
|
+
expect(nil_chain{ params[:foo] }).to eq 'bar'
|
11
|
+
var = 'a simple string'
|
12
|
+
expect(nil_chain{ var.transmogrify }).to eq nil
|
13
|
+
|
14
|
+
c = C.new
|
15
|
+
b = B.new c
|
16
|
+
a = A.new b
|
17
|
+
expect(a.b.c.hello).to eq "Hello, world!"
|
18
|
+
b.c = nil
|
19
|
+
expect(method_chain{a.b.c.hello}).to eq nil
|
20
|
+
a = nil
|
21
|
+
expect(method_chain{a.b.c.hello}).to eq nil
|
22
|
+
|
23
|
+
expect( chain(true) { bogus_variable } ).to equal true
|
24
|
+
expect( chain(false) { bogus_variable } ).to equal false
|
25
|
+
expect( chain('gotcha!') { bogus_variable } ).to eq 'gotcha!'
|
26
|
+
expect( chain('gotcha!') { params[:bogus_key] } ).to eq 'gotcha!'
|
27
|
+
expect( chain('gotcha!') { params[:foo] } ).to eq 'bar'
|
28
|
+
end
|
29
|
+
|
30
|
+
it "#bool_chain" do
|
31
|
+
expect(bool_chain{bogus_variable}).to equal false
|
32
|
+
var = true
|
33
|
+
expect(bool_chain{var}).to equal true
|
34
|
+
var = 'foo'
|
35
|
+
expect(bool_chain{var}).to eq 'foo'
|
36
|
+
result = bool_chain{ var.transmogrify }
|
37
|
+
expect(result).to equal false
|
38
|
+
end
|
39
|
+
|
40
|
+
it "#class_exists?" do
|
41
|
+
expect(class_exists? :Symbol).to eq true
|
42
|
+
expect(class_exists? :Symbology).to eq false
|
43
|
+
expect(class_exists? 'Symbol').to eq true
|
44
|
+
expect(class_exists? 'Symbology').to eq false
|
45
|
+
expect(class_exists? :Array).to eq true
|
46
|
+
expect(class_exists? :aRRay).to eq false
|
47
|
+
expect(class_exists? :ARRAY).to eq false
|
48
|
+
end
|
49
|
+
|
50
|
+
it "#not_nil?" do
|
51
|
+
var = nil
|
52
|
+
expect(var.not_nil?).to eq false
|
53
|
+
var = 'foobar'
|
54
|
+
expect(var.not_nil?).to eq true
|
55
|
+
end
|
56
|
+
|
57
|
+
it "#same_as" do
|
58
|
+
expect(:symbol.same_as 'symbol').to eq true
|
59
|
+
expect('symbol'.same_as :symbol).to eq true
|
60
|
+
expect('1'.same_as 1).to eq true
|
61
|
+
expect(2.same_as '2').to eq true
|
62
|
+
expect(3.same_as 3).to eq true
|
63
|
+
expect(:symbol.same_as :SYMBOL).to eq false
|
64
|
+
|
65
|
+
user = User.new
|
66
|
+
expect(:faceless_one.same_as(user)).to eq true
|
67
|
+
expect(user.same_as(:faceless_one)).to eq true
|
68
|
+
expect(user.same_as(:FACELESS_ONE)).to eq false
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
# test classes
|
74
|
+
|
75
|
+
class A
|
76
|
+
attr_accessor :b
|
77
|
+
def initialize(b)
|
78
|
+
@b = b
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class B
|
83
|
+
attr_accessor :c
|
84
|
+
def initialize(c)
|
85
|
+
@c = c
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class C
|
90
|
+
def hello
|
91
|
+
"Hello, world!"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class User
|
96
|
+
attr_writer :handle
|
97
|
+
|
98
|
+
def handle
|
99
|
+
@handle || "faceless_one"
|
100
|
+
end
|
101
|
+
|
102
|
+
def to_s
|
103
|
+
handle.to_s
|
104
|
+
end
|
105
|
+
end
|