finishing_moves 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
+