finishing_moves 0.2.0 → 0.3.0

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.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ desc "Open an irb session preloaded with this library"
2
+ task :console do
3
+ sh "irb -rubygems -I lib -r finishing_moves.rb"
4
+ end
5
+ task :c => :console
6
+
7
+ desc "Build the gem according to gemspec"
8
+ task :buildgem do
9
+ sh "gem build finishing_moves.gemspec"
10
+ end
@@ -26,4 +26,19 @@ Gem::Specification.new do |s|
26
26
  s.add_development_dependency 'fuubar', '>= 0'
27
27
 
28
28
  s.required_ruby_version = '>= 2.0'
29
+
30
+ s.post_install_message = <<EOS
31
+ ********************************************************************************
32
+
33
+ Thank you for installing Finishing Moves!
34
+
35
+ Built and maintained by Forge Software
36
+ www.forgecrafted.com
37
+
38
+ Does your project or organization use this gem? Add it to the showcase page.
39
+ https://github.com/forgecrafted/finishing_moves/wiki/showcase
40
+
41
+ ********************************************************************************
42
+ EOS
43
+
29
44
  end
@@ -0,0 +1,30 @@
1
+ class Array
2
+
3
+ def to_hash_values(starting_key = 0, &block)
4
+ key = starting_key
5
+ block = proc { |key| key + 1 } unless block_given?
6
+ t = {}
7
+ each do |entry|
8
+ t[key] = entry
9
+ key = block.call key
10
+ end
11
+ t
12
+ end
13
+ alias_method :to_hash_as_values, :to_hash_values
14
+
15
+ def to_indexed_hash(starting_key = 0)
16
+ raise ArgumentError, "#{starting_key.inspect} is not an integer" unless starting_key.is_a? Integer
17
+ to_hash_values(starting_key) { |i| i + 1 }
18
+ end
19
+
20
+ def to_hash_keys(starting_value = 0, &block)
21
+ t = {}
22
+ block = proc { default_value } unless block_given?
23
+ each do |entry|
24
+ t[entry] = block.call entry
25
+ end
26
+ t
27
+ end
28
+ alias_method :to_hash_as_keys, :to_hash_keys
29
+
30
+ end
@@ -0,0 +1,25 @@
1
+ module FinishingMovesFiscalLogic
2
+
3
+ def fiscal_quarter
4
+ ((self.month - 1) / 3) + 1
5
+ end
6
+
7
+ # return array of month integers correspond to appropriate quarter interger
8
+ def quarter_months
9
+ quarters = [[1,2,3], [4,5,6], [7,8,9], [10,11,12]]
10
+ quarters[self.month - 1]
11
+ end
12
+
13
+ end
14
+
15
+ class Time
16
+ include FinishingMovesFiscalLogic
17
+ end
18
+
19
+ class Date
20
+ include FinishingMovesFiscalLogic
21
+ end
22
+
23
+ class DateTime
24
+ include FinishingMovesFiscalLogic
25
+ end
@@ -0,0 +1,18 @@
1
+ module Enumerable
2
+
3
+ def key_map(key)
4
+ map { |h| h[key] }
5
+ end
6
+
7
+ def key_map_reduce(key, arg = :+, &block)
8
+ if block_given?
9
+ # arg is the initial value of memo
10
+ key_map(key).reduce(arg, &block)
11
+ else
12
+ # arg is a named method
13
+ raise ArgumentError.new "arg must be a method symbol" unless arg.is_a? Symbol
14
+ key_map(key).reduce(arg)
15
+ end
16
+ end
17
+
18
+ end
@@ -1,23 +1,20 @@
1
- class Fixnum
2
- def length
3
- Math.log10(self.abs).to_i + 1
4
- end
5
- end
6
-
7
- class Bignum
1
+ class Integer
8
2
  def length
9
3
  Math.log10(self.abs).to_i + 1
10
4
  end
5
+ alias_method :digits, :length
11
6
  end
12
7
 
13
8
  class Float
14
9
  def length
15
10
  raise ArgumentError.new("Cannot get length: \"#{self}\" is not an integer")
16
11
  end
12
+ alias_method :digits, :length
17
13
  end
18
14
 
19
15
  class BigDecimal
20
16
  def length
21
17
  raise ArgumentError.new("Cannot get length: \"#{self}\" is not an integer")
22
18
  end
19
+ alias_method :digits, :length
23
20
  end
@@ -0,0 +1,35 @@
1
+ module Kernel
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 :method_chain, :nil_chain
14
+
15
+ def bool_chain(&block)
16
+ result = nil_chain(&block)
17
+ return false if result.nil?
18
+ result
19
+ end
20
+
21
+ def class_exists?(class_name)
22
+ klass = Module.const_get(class_name.to_s)
23
+ return klass.is_a?(Class)
24
+ rescue NameError
25
+ return false
26
+ end
27
+
28
+ def cascade(&block)
29
+ loop do
30
+ yield
31
+ break
32
+ end
33
+ end
34
+
35
+ end
@@ -1,34 +1,11 @@
1
1
  class Object
2
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 :method_chain, :nil_chain
14
-
15
- def bool_chain(&block)
16
- result = nil_chain(&block)
17
- return false if result.nil?
18
- result
19
- end
20
-
21
- def class_exists?(class_name)
22
- klass = Module.const_get(class_name.to_s)
23
- return klass.is_a?(Class)
24
- rescue NameError
25
- return false
26
- end
27
-
28
3
  def not_nil?
29
4
  !self.nil?
30
5
  end
31
6
 
7
+ alias_method :is_an?, :is_a?
8
+
32
9
  def same_as(compare)
33
10
  if compare.respond_to? :to_s
34
11
  self.to_s == compare.to_s
@@ -36,12 +13,12 @@ class Object
36
13
  raise ArgumentError.new("Cannot compare \"#{self.class.name}\" to \"#{compare.class.name}\", no string conversion")
37
14
  end
38
15
  end
16
+ alias_method :same_as?, :same_as
39
17
 
40
- def cascade(&block)
41
- loop do
42
- yield
43
- break
44
- end
18
+ # Allows us to call keyify directly on a class name.
19
+ # See keyify() in string.rb for details.
20
+ def self.keyify
21
+ name.keyify
45
22
  end
46
23
 
47
24
  end
@@ -0,0 +1,127 @@
1
+ class String
2
+
3
+ def nl2br
4
+ self.gsub(/(?:\n\r?|\r\n?)/, "<br />\n")
5
+ end
6
+
7
+ def keyify
8
+ result = nil_chain do
9
+ the_key = self.clone
10
+
11
+ # strip all non-alphanumerics
12
+ the_key.gsub!(/[^0-9a-z]+/i, '_')
13
+
14
+ # borrowing some logic from Rails method underscore
15
+ # http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-underscore
16
+ if the_key =~ /[A-Z-]|::/
17
+ the_key.gsub!(/::/, '_')
18
+ the_key.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
19
+ the_key.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
20
+ end
21
+
22
+ # Strip any leading numbers and underscores
23
+ the_key.lstrip_all!('0-9_')
24
+ # Strip trailing underscores
25
+ the_key.rstrip_all!('_')
26
+ # Combine multiple concurrent underscores
27
+ the_key.dedupe!('_')
28
+ # lowercase
29
+ the_key.downcase!
30
+ next the_key
31
+ end
32
+ return nil if result.nil? || result == ''
33
+ result.to_sym
34
+ end
35
+
36
+ def keyify!
37
+ result = self.keyify
38
+ raise ArgumentError, "#{self.inspect} cannot be keyified, no valid characters" if result.nil?
39
+ result
40
+ end
41
+
42
+ def strip_all(chars = nil)
43
+ expr = _strip_all_prep(chars)
44
+ gsub Regexp.union(_lstrip_all_regex(expr), _rstrip_all_regex(expr)), ''
45
+ end
46
+
47
+ def strip_all!(chars = nil)
48
+ expr = _strip_all_prep(chars)
49
+ gsub! Regexp.union(_lstrip_all_regex(expr), _rstrip_all_regex(expr)), ''
50
+ end
51
+
52
+ def lstrip_all(chars = nil)
53
+ gsub _lstrip_all_regex(_strip_all_prep(chars)), ''
54
+ end
55
+
56
+ def lstrip_all!(chars = nil)
57
+ gsub! _lstrip_all_regex(_strip_all_prep(chars)), ''
58
+ end
59
+
60
+ def rstrip_all(chars = nil)
61
+ gsub _rstrip_all_regex(_strip_all_prep(chars)), ''
62
+ end
63
+
64
+ def rstrip_all!(chars = nil)
65
+ gsub! _rstrip_all_regex(_strip_all_prep(chars)), ''
66
+ end
67
+
68
+ # strip multiple concurrent characters
69
+ def dedupe(str)
70
+ raise ArgumentError, "#{str.inspect} is not a string" unless str.is_a? String
71
+ # Yes, this is inefficient. We welcome optimizations from the regex ninjas out there.
72
+ ret = String.new self
73
+ str.each_char { |c| ret.gsub! /#{Regexp.escape c}{2,}/, c }
74
+ ret
75
+ end
76
+
77
+ def dedupe!(str)
78
+ raise ArgumentError, "#{str.inspect} is not a string" unless str.is_a? String
79
+ # Yes, this is inefficient. We welcome optimizations from the regex ninjas out there.
80
+ str.each_char { |c| gsub! /#{Regexp.escape c}{2,}/, c }
81
+ end
82
+
83
+ def remove_whitespace(replace = '')
84
+ gsub /[ ]/, replace
85
+ end
86
+
87
+ def remove_whitespace!(replace = '')
88
+ gsub! /[ ]/, replace
89
+ end
90
+
91
+ # return true/false on regex match
92
+ def match?(pattern, pos = 0)
93
+ match(pattern, pos).not_nil?
94
+ end
95
+
96
+ protected
97
+
98
+ def _lstrip_all_regex(expr)
99
+ /\A[#{expr}]+/
100
+ end
101
+
102
+ def _rstrip_all_regex(expr)
103
+ /[#{expr}]+\Z/
104
+ end
105
+
106
+ def _strip_all_prep(chars)
107
+ chars = '-_' if chars.nil?
108
+ raise ArgumentError, "#{chars.inspect} is not a string" unless chars.is_a? String
109
+
110
+ expr = Regexp.escape( chars.gsub(/(0-9)+|(a-z)+|(A-Z)+|\s+/, '').strip )
111
+ ['0-9', 'a-z', 'A-Z'].each do |range|
112
+ expr << range if chars.include? range
113
+ end
114
+ expr << ' '
115
+ end
116
+
117
+ end
118
+
119
+ # We aren't reopening Symbol class for anything else yet, so we'll just define
120
+ # it in this file.
121
+ class Symbol
122
+
123
+ def keyify
124
+ to_s.keyify
125
+ end
126
+
127
+ end
@@ -1,3 +1,3 @@
1
1
  module FinishingMoves
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/provision.sh CHANGED
@@ -18,7 +18,6 @@ as_user() {
18
18
  install_ruby() {
19
19
  as_user "rbenv install -s $1"
20
20
  as_user "RBENV_VERSION=$1 gem install bundler"
21
- as_user "rbenv rehash"
22
21
  }
23
22
 
24
23
  ###############################################################################
@@ -47,7 +46,6 @@ apt-get install -yfV \
47
46
  libyaml-dev \
48
47
  python-software-properties \
49
48
  sqlite3 \
50
- wget \
51
49
  zlib1g-dev \
52
50
 
53
51
  # Install rbenv and ruby-build.
@@ -55,6 +53,7 @@ as_user "git clone https://github.com/sstephenson/rbenv.git $USER_HOME/.rbenv"
55
53
  as_user "git clone https://github.com/sstephenson/ruby-build.git $USER_HOME/.rbenv/plugins/ruby-build"
56
54
 
57
55
  # Setup bash to use rbenv for $USER_NAME.
56
+ truncate -s 0 $USER_HOME/.bashrc
58
57
  echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> $USER_HOME/.bashrc
59
58
  echo 'eval "$(rbenv init -)"' >> $USER_HOME/.bashrc
60
59
  echo 'cd /vagrant' >> $USER_HOME/.bashrc
@@ -0,0 +1,127 @@
1
+ require 'spec_helper'
2
+
3
+ describe Array do
4
+
5
+ let :sages do
6
+ ['Rauru', 'Saria', 'Darunia', 'Princess Ruto', 'Impa', 'Nabooru', 'Zelda']
7
+ end
8
+
9
+ it '#to_indexed_hash' do
10
+ expect { sages.to_indexed_hash("e") }.to raise_error(ArgumentError)
11
+ sages_hash = sages.to_indexed_hash
12
+ i = 0
13
+ sages.each do |sage|
14
+ expect(sages_hash[i]).to eq sage
15
+ i += 1
16
+ end
17
+
18
+ sages_hash = sages.to_indexed_hash(22)
19
+ i = 22
20
+ sages.each do |sage|
21
+ expect(sages_hash[i]).to eq sage
22
+ i += 1
23
+ end
24
+ end
25
+
26
+ it '#to_hash_values <#to_indexed_hash behaviour>' do
27
+ sages_hash = sages.to_hash_values
28
+ i = 0
29
+ sages.each do |sage|
30
+ expect(sages_hash[i]).to eq sage
31
+ i += 1
32
+ end
33
+
34
+ block = proc { |key| key + 1 }
35
+ sages_hash = sages.to_hash_values 0, &block
36
+ i = 0
37
+ sages.each do |sage|
38
+ expect(sages_hash[i]).to eq sage
39
+ i += 1
40
+ end
41
+
42
+ sages_hash = sages.to_hash_values(22)
43
+ i = 22
44
+ sages.each do |sage|
45
+ expect(sages_hash[i]).to eq sage
46
+ i += 1
47
+ end
48
+ end
49
+
50
+ it '#to_hash_values' do
51
+ block = proc { |key| key + 3 }
52
+ sages_hash = sages.to_hash_values 0, &block
53
+ i = 0
54
+ sages.each do |sage|
55
+ expect(sages_hash[i]).to eq sage
56
+ i += 3
57
+ end
58
+
59
+ sages_hash = sages.to_hash_values 22, &block
60
+ i = 22
61
+ sages.each do |sage|
62
+ expect(sages_hash[i]).to eq sage
63
+ i += 3
64
+ end
65
+
66
+ # alias check
67
+ expect(sages.to_hash_as_values(22, &block)).to eq sages_hash
68
+
69
+ elements = SageElements.new
70
+ sages_hash = sages.to_hash_values(elements.first_key) do |key|
71
+ elements.next_key(key)
72
+ end
73
+ expect(sages_hash[:light]).to eq sages[0]
74
+ expect(sages_hash[:forest]).to eq sages[1]
75
+ expect(sages_hash[:fire]).to eq sages[2]
76
+ expect(sages_hash[:water]).to eq sages[3]
77
+ expect(sages_hash[:shadow]).to eq sages[4]
78
+ expect(sages_hash[:spirit]).to eq sages[5]
79
+ expect(sages_hash[:time]).to eq sages[6]
80
+ end
81
+
82
+ it '#to_hash_keys' do
83
+ sages_hash = sages.to_hash_keys
84
+ # alias check
85
+ expect(sages.to_hash_as_keys).to eq sages_hash
86
+
87
+ sages.each do |sage|
88
+ expect(sages_hash[sage]).to eq 0
89
+ end
90
+
91
+ sages_hash = sages.to_hash_keys('foobar')
92
+ sages.each do |sage|
93
+ expect(sages_hash[sage]).to eq 'foobar'
94
+ end
95
+
96
+ sages_hash = sages.to_hash_keys { |key| key + "1" }
97
+ sages.each do |sage|
98
+ expect(sages_hash[sage]).to eq sage + "1"
99
+ end
100
+ end
101
+
102
+ end
103
+
104
+ class SageElements
105
+
106
+ def initialize
107
+ @keys = {
108
+ :first => :light,
109
+ :light => :forest,
110
+ :forest => :fire,
111
+ :fire => :water,
112
+ :water => :shadow,
113
+ :shadow => :spirit,
114
+ :spirit => :time,
115
+ :time => :first,
116
+ }
117
+ end
118
+
119
+ def first_key
120
+ @keys[:first]
121
+ end
122
+
123
+ def next_key(pointer)
124
+ @keys[pointer]
125
+ end
126
+
127
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Enumerable do
4
+
5
+ let :test_array do
6
+ [
7
+ {:foo => 1, :bar => 5, :baz => 9},
8
+ {:foo => 2, :bar => 6, :baz => 10},
9
+ {:foo => 3, :bar => 7, :baz => 11},
10
+ {:foo => 4, :bar => 8, :baz => 12},
11
+ ]
12
+ end
13
+
14
+ it "#key_map" do
15
+ expect(test_array.key_map :foo).to eq([1, 2, 3, 4])
16
+ expect(test_array.key_map :bar).to eq([5, 6, 7, 8])
17
+ expect(test_array.key_map :baz).to eq([9, 10, 11, 12])
18
+ end
19
+
20
+ context "#key_map_reduce" do
21
+ it "default behavior" do
22
+ expect(test_array.key_map_reduce :foo).to eq(10)
23
+ expect(test_array.key_map_reduce :bar).to eq(26)
24
+ expect(test_array.key_map_reduce :baz).to eq(42)
25
+ end
26
+ it "with method override" do
27
+ expect(test_array.key_map_reduce :foo, :*).to eq(24)
28
+ expect(test_array.key_map_reduce :bar, :*).to eq(1680)
29
+ expect(test_array.key_map_reduce :baz, :*).to eq(11880)
30
+ end
31
+ it "with block" do
32
+ actual = test_array.key_map_reduce(:bar, "") { |memo,x| memo + "#{x**2}," }
33
+ expect(actual).to eq("25,36,49,64,")
34
+ end
35
+ end
36
+
37
+ end
data/spec/fixnum_spec.rb CHANGED
@@ -10,11 +10,15 @@ describe "Count number length" do
10
10
  expect(900.length).to eq 3
11
11
  expect(9000.length).to eq 4
12
12
  expect(-9000.length).to eq 4
13
+ # alias
14
+ expect(-9000.digits).to eq 4
13
15
  end
14
16
 
15
17
  it "Bignum#length" do
16
18
  expect(12356469787881584554556.length).to eq 23
17
19
  expect(-12356469787881584554556.length).to eq 23
20
+ # alias
21
+ expect(-12356469787881584554556.digits).to eq 23
18
22
  end
19
23
 
20
24
  it "Float#length" do
@@ -23,6 +27,8 @@ describe "Count number length" do
23
27
  expect{ -1.0.length }.to raise_error(ArgumentError)
24
28
  expect{ 3.14.length }.to raise_error(ArgumentError)
25
29
  expect{ 12356469.987.length }.to raise_error(ArgumentError)
30
+ # alias
31
+ expect{ 12356469.987.digits }.to raise_error(ArgumentError)
26
32
  end
27
33
 
28
34
  it "BigDecimal#length" do
@@ -30,6 +36,8 @@ describe "Count number length" do
30
36
  expect{ -1265437718438866624512.123.length }.to raise_error(ArgumentError)
31
37
  expect{ 0.9999999999999062.length }.to raise_error(ArgumentError)
32
38
  expect{ -0.9999999999999062.length }.to raise_error(ArgumentError)
39
+ # alias
40
+ expect{ -0.9999999999999062.digits }.to raise_error(ArgumentError)
33
41
  end
34
42
 
35
43
  end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+
3
+ describe Kernel 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(nil_chain{a.b.c.hello}).to eq nil
20
+ a = nil
21
+ expect(nil_chain{a.b.c.hello}).to eq nil
22
+
23
+ expect( nil_chain(true) { bogus_variable } ).to equal true
24
+ expect( nil_chain(false) { bogus_variable } ).to equal false
25
+ expect( nil_chain('gotcha!') { bogus_variable } ).to eq 'gotcha!'
26
+ expect( nil_chain('gotcha!') { params[:bogus_key] } ).to eq 'gotcha!'
27
+ expect( nil_chain('gotcha!') { params[:foo] } ).to eq 'bar'
28
+
29
+ # alias
30
+ expect(method_chain{bogus_variable}).to eq nil
31
+ end
32
+
33
+ it "#bool_chain" do
34
+ expect(bool_chain{bogus_variable}).to equal false
35
+ var = true
36
+ expect(bool_chain{var}).to equal true
37
+ var = 'foo'
38
+ expect(bool_chain{var}).to eq 'foo'
39
+ result = bool_chain{ var.transmogrify }
40
+ expect(result).to equal false
41
+ end
42
+
43
+ it "#class_exists?" do
44
+ expect(class_exists? :Symbol).to eq true
45
+ expect(class_exists? :Symbology).to eq false
46
+ expect(class_exists? 'Symbol').to eq true
47
+ expect(class_exists? 'Symbology').to eq false
48
+ expect(class_exists? :Array).to eq true
49
+ expect(class_exists? :aRRay).to eq false
50
+ expect(class_exists? :ARRAY).to eq false
51
+ expect(class_exists? 'SomeModule::ClassInModule').to eq true
52
+ end
53
+
54
+ it "#cascade" do
55
+ expect(test_cascade).to be_nil
56
+ expect(test_cascade('step1')).to eq 1
57
+ expect(test_cascade('step2')).to eq 2
58
+ expect(test_cascade('step3')).to eq 3
59
+ expect(test_cascade('foobar')).to eq 4
60
+ end
61
+
62
+ end
63
+
64
+ # some small test fixtures
65
+
66
+ class A
67
+ attr_accessor :b
68
+ def initialize(b)
69
+ @b = b
70
+ end
71
+ end
72
+
73
+ class B
74
+ attr_accessor :c
75
+ def initialize(c)
76
+ @c = c
77
+ end
78
+ end
79
+
80
+ class C
81
+ def hello
82
+ "Hello, world!"
83
+ end
84
+ end
85
+
86
+ class User
87
+ attr_writer :handle
88
+
89
+ def handle
90
+ @handle || "faceless_one"
91
+ end
92
+
93
+ def to_s
94
+ handle.to_s
95
+ end
96
+ end
97
+
98
+ def test_cascade(trigger = nil)
99
+ ultimate_value = nil
100
+ cascade do
101
+ break if trigger.nil?
102
+ ultimate_value = 1
103
+ break if trigger == 'step1'
104
+ ultimate_value = 2
105
+ break if trigger == 'step2'
106
+ ultimate_value = 3
107
+ break if trigger == 'step3'
108
+ ultimate_value = 4
109
+ end
110
+ return ultimate_value
111
+ end
112
+
113
+ module SomeModule
114
+ class ClassInModule
115
+ end
116
+ end
117
+