duck_puncher 2.3.0 → 2.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ee22023f5904a77f13fdc09ac72eefa9170938ea
4
- data.tar.gz: 28fb5cc8000d7de6240b6cf6c41e476861c4e255
3
+ metadata.gz: d30be8964065fb57d3de53e4e23b2deaf8ceb277
4
+ data.tar.gz: f2bc471c1a31a1f438680f21440b86d489092cd1
5
5
  SHA512:
6
- metadata.gz: fb0141394a399c457e4650f607ed66c7c924aa9c7e15030faafd1c20a18d812b620bc13864bcda8904720aa1218f65d915fdf8601af4e6dc4c412ebb722a0523
7
- data.tar.gz: 9f86ea17b513e5e3e0e4da59c6665c398e6f26b8229b9d58f5f012578147577ad7755ef1775626f75ab69063159abf45b00acb03c323ff583905c52c2fbe98ec
6
+ metadata.gz: e117be77a8e6a2a80f0ba415315039fa727ba1495e52bfa9b83cd7b5d631b92ebce331eaac51f6b7fb2d5c76a00e2f88f19892f4f84039686fab277976a40588
7
+ data.tar.gz: 64a2e78858356beacb9f30ea6cd6955046c8f90fc596fd0d15c64cbe2e121423e85b9ffe384e08826655f45eddc74bae824a6c401877e65ebf62c44908adc851
data/README.md CHANGED
@@ -2,33 +2,42 @@
2
2
 
3
3
  These are the ducks I can punch:
4
4
 
5
- Array#m => `[].m(:to_s)` alias for `[].map(&:to_s)`
6
- Array#mm => `[].mm(:sub, /[aeiou]/, '*')` alias for `[].map { |x| x.sub(/[aeiou]/, '*') }`
7
- Array#get => `[].methods.get('ty?')` searches the array for a string matching the 'ty?' (e.g. [:empty?])
8
- Hash#seek => `{a: 1, b: {c: 2}}.seek(:b, :c)` returns the value of nested hash keys (e.g. 2)
9
- Numeric#to_currency => `25.245.to_currency` formats a number in currency (e.g. '25.25' or '1.00')
10
- Numeric#to_duration => `10_000.to_duration` turns a number into duration (e.g. '2 h 46 min')
11
- Numeric#to_time_ago => `10_000.to_time_ago` turns a number into time ago (e.g. '2 hours ago')
12
- Numeric#to_rad => `10.15.to_rad` returns 0.17715091907742445
13
- String#pluralize => `'hour'.pluralize(2)` turns "hour" into "hours"
14
- Object#clone! => `Object.new.clone!` makes a deep clone of the object (using Marshal)
15
- Object#require! => Downloads and activates a gem for the current and subsequent consoles. For example:
16
- >> `require 'pry'`
17
- LoadError: cannot load such file -- pry
18
- from (irb):1:in `require'
19
- from (irb):1
20
- from bin/console:10:in `<main>'
21
- >> require! 'pry'
22
- Fetching: method_source-0.8.2.gem (100%)
23
- Fetching: slop-3.6.0.gem (100%)
24
- Fetching: coderay-1.1.0.gem (100%)
25
- Fetching: pry-0.10.3.gem (100%)
26
- => true
27
- >> Pry.start
28
- [1] pry(main)>
5
+ Array#m => `[].m(:to_s)` => `[].map(&:to_s)`
6
+ Array#mm => `[].mm(:sub, /[aeiou]/, '*')` => `[].map { |x| x.sub(/[aeiou]/, '*') }`
7
+ Array#get => `[].methods.get('ty?')` => [:empty?]
8
+ Hash#seek => `{a: 1, b: {c: 2}}.seek(:b, :c)` => 2
9
+ Numeric#to_currency => `25.245.to_currency` => 25.25
10
+ Numeric#to_duration => `10_000.to_duration` => '2 h 46 min'
11
+ Numeric#to_time_ago => `10_000.to_time_ago` => '2 hours ago'
12
+ Numeric#to_rad => `10.15.to_rad` => 0.17715091907742445
13
+ String#pluralize => `'hour'.pluralize(2)` => "hours"
14
+ String#underscore => `'DuckPuncher::JSONStorage'.underscore` => 'duck_puncher/json_storage'
15
+ Object#clone! => `Object.new.clone!` => a deep clone of the object (using Marshal.dump)
29
16
  Method#to_instruct => `Benchmark.method(:measure).to_instruct` returns the Ruby VM instruction sequence for the method
30
17
  Method#to_source => `Benchmark.method(:measure).to_source` returns the method definition as a string
18
+
19
+ I also provide an experimental punch that tries to download the required gem if it doesn't exist on your computer. The
20
+ method is called `require!` and works like this:
21
+
22
+ Downloads and activates a gem for the current and subsequent consoles. For example:
23
+
24
+ ```bash
25
+ >> `require 'pry'`
26
+ LoadError: cannot load such file -- pry
27
+ from (irb):1:in `require'
28
+ from (irb):1
29
+ from bin/console:10:in `<main>'
30
+ >> require! 'pry'
31
+ Fetching: method_source-0.8.2.gem (100%)
32
+ Fetching: slop-3.6.0.gem (100%)
33
+ Fetching: coderay-1.1.0.gem (100%)
34
+ Fetching: pry-0.10.3.gem (100%)
35
+ => true
36
+ >> Pry.start
37
+ [1] pry(main)>
38
+ ```
31
39
 
40
+ Try it out if your feeling frisky! However, I noticed it doesn't work well with bigger gems and those with native extensions.
32
41
 
33
42
  ## Install
34
43
 
data/bin/console CHANGED
@@ -5,6 +5,7 @@ require 'pp'
5
5
  require 'duck_puncher'
6
6
  require 'irb'
7
7
  require_relative '../test/fixtures/wut'
8
+
8
9
  DuckPuncher.punch_all!
9
10
 
10
11
  IRB.start
@@ -0,0 +1,30 @@
1
+ module DuckPuncher
2
+ class Duck
3
+ attr_accessor :name, :options
4
+
5
+ def initialize(name, options = {})
6
+ @name = name
7
+ @options = options
8
+ @punched = false
9
+ end
10
+
11
+ def load_path
12
+ "duck_puncher/ducks/#{name.to_s.downcase}"
13
+ end
14
+
15
+ def punch
16
+ return false if options[:if] && !options[:if].call
17
+ options[:before].call if options[:before]
18
+ const.send :include, DuckPuncher::Ducks.const_get(name)
19
+ @punched = true
20
+ end
21
+
22
+ def const
23
+ @const ||= (options[:class] || name).to_s.split('::').inject(Kernel) { |k, part| k.const_get part }
24
+ end
25
+
26
+ def punched?
27
+ @punched
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,48 @@
1
+ module DuckPuncher
2
+ module ActiveRecord
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ def associations?
8
+ associations.present?
9
+ end
10
+
11
+ def associations
12
+ reflections.select { |key, _| send(key).present? rescue nil }.keys
13
+ end
14
+
15
+ module ClassMethods
16
+ def except_for(*ids)
17
+ scoped.where("#{quoted_table_name}.id NOT IN (?)", ids)
18
+ end
19
+
20
+ def since(time)
21
+ scoped.where("#{quoted_table_name}.created_at > ?", time)
22
+ end
23
+
24
+ alias created_since since
25
+
26
+ def before(time)
27
+ scoped.where("#{quoted_table_name}.created_at < ?", time)
28
+ end
29
+
30
+ def updated_since(time)
31
+ scoped.where("#{quoted_table_name}.updated_at > ?", time)
32
+ end
33
+
34
+ def between(start_at, end_at)
35
+ scoped.where("#{quoted_table_name}.created_at BETWEEN ? AND ", start_at, end_at)
36
+ end
37
+
38
+ def latest
39
+ scoped.order("#{quoted_table_name}.id ASC").last
40
+ end
41
+
42
+ # shim for backwards compatibility with Rails 3
43
+ def scoped
44
+ where(nil)
45
+ end if Rails::VERSION::MAJOR != 3
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,18 @@
1
+ module DuckPuncher
2
+ module Ducks
3
+ module Array
4
+ def m(method_name)
5
+ map(&method_name)
6
+ end
7
+
8
+ def mm(method_name, *args)
9
+ map { |x| x.public_send(method_name, *args) }
10
+ end
11
+
12
+ def get(regex_or_str)
13
+ regex = regex_or_str.is_a?(Regexp) ? regex_or_str : Regexp.new(Regexp.escape(regex_or_str))
14
+ select { |x| x.to_s =~ regex }
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ module DuckPuncher
2
+ module Ducks
3
+ module Hash
4
+ # http://coryodaniel.com/index.php/2009/12/30/ruby-getting-deeply-nested-values-from-a-hash-in-one-line-of-code/
5
+ def seek(*_keys_)
6
+ last_level = self
7
+ sought_value = nil
8
+
9
+ _keys_.each_with_index do |_key_, _idx_|
10
+ if last_level.is_a?(Hash) && last_level.has_key?(_key_)
11
+ if _idx_ + 1 == _keys_.length
12
+ sought_value = last_level[_key_]
13
+ else
14
+ last_level = last_level[_key_]
15
+ end
16
+ else
17
+ break
18
+ end
19
+ end
20
+
21
+ sought_value
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,56 @@
1
+ module DuckPuncher
2
+ module Ducks
3
+ module Method
4
+ def to_instruct
5
+ definition = Definition.new(self)
6
+ RubyVM::InstructionSequence.new(definition.lines.join).disasm if definition.lines.any?
7
+ end
8
+
9
+ def to_source
10
+ Definition.new(self).to_s
11
+ end
12
+
13
+ class Definition
14
+ def initialize(method_handle)
15
+ @file_path, @line_num = *method_handle.source_location
16
+ @line_num = @line_num.to_i
17
+ end
18
+
19
+ # @description finds the method's source code using the indent size of the file. This means we are
20
+ # restricted when it comes to parsing crappy formatted ruby files
21
+ def lines
22
+ return @lines if defined? @lines
23
+ return [] unless @file_path
24
+ @lines = []
25
+ File.open(@file_path) do |f|
26
+ found = false
27
+ i = 0
28
+ while line = f.gets and i += 1 and !found
29
+ next if i < @line_num
30
+ @lines << line
31
+ if @indent_size
32
+ found = @indent_size == find_indent_size(line)
33
+ else
34
+ @indent_size = find_indent_size(line)
35
+ found = line.end_with?("end\n")
36
+ end
37
+ end
38
+ end
39
+ @lines
40
+ end
41
+
42
+ def to_s
43
+ if lines.any?
44
+ lines.join.gsub /^\s{#{find_indent_size(lines.first)}}/, ''
45
+ else
46
+ ''
47
+ end
48
+ end
49
+
50
+ def find_indent_size(line)
51
+ line[/(\s*)/].size
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,51 @@
1
+ module DuckPuncher
2
+ module Ducks
3
+ module Numeric
4
+ def to_currency(prefix = '')
5
+ "#{prefix}%.2f" % self.round(2)
6
+ end
7
+
8
+ def to_duration(seconds = false)
9
+ secs = to_i
10
+ mins = secs / 60
11
+ hours = mins / 60
12
+ buffer = ''
13
+ if hours > 0
14
+ num_mins = mins % 60
15
+ buffer << "#{hours} h"
16
+ buffer << " #{num_mins} min" unless num_mins.zero?
17
+ elsif mins > 0
18
+ num_secs = secs % 60
19
+ buffer << "#{mins} min"
20
+ buffer << " #{num_secs} s" if seconds && num_secs.nonzero?
21
+ elsif seconds && secs >= 0
22
+ buffer << "#{secs} s"
23
+ end
24
+ buffer
25
+ end
26
+
27
+ # similar to Rails' #time_ago_in_words
28
+ def to_time_ago
29
+ secs = to_i
30
+ mins = secs / 60
31
+ hours = mins / 60
32
+ days = hours / 24
33
+ buffer = ''
34
+ if days > 0
35
+ buffer << "#{days} #{'day'.pluralize(days)}"
36
+ elsif hours > 0
37
+ buffer << "#{hours} #{'hour'.pluralize(hours)}"
38
+ elsif mins > 0
39
+ buffer << "#{mins} #{'minute'.pluralize(mins)}"
40
+ elsif secs >= 0
41
+ buffer << "less than a minute"
42
+ end
43
+ buffer << ' ago'
44
+ end
45
+
46
+ def to_rad
47
+ self / 180 * Math::PI
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,15 @@
1
+ module DuckPuncher
2
+ module Ducks
3
+ module Object
4
+ def clone!
5
+ Marshal.load Marshal.dump self
6
+ end unless defined? clone!
7
+
8
+ def require!(file_or_gem, version = '')
9
+ if DuckPuncher::GemInstaller.new.perform(file_or_gem, version)
10
+ require file_or_gem.tr('-', '/')
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ module DuckPuncher
2
+ module Ducks
3
+ module String
4
+ def pluralize(count)
5
+ "#{self}#{'s' if count != 1}"
6
+ end unless method_defined?(:pluralize)
7
+
8
+ def underscore
9
+ gsub(/\B([A-Z])([a-z_0-9])/, '_\1\2').gsub('::', '/').downcase
10
+ end unless method_defined?(:underscore)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,29 @@
1
+ module DuckPuncher
2
+ module Ducks
3
+ class << self
4
+ def list
5
+ @list ||= [
6
+ Duck.new(:Array),
7
+ Duck.new(:Numeric),
8
+ Duck.new(:Hash),
9
+ Duck.new(:String),
10
+ Duck.new(:Object),
11
+ Duck.new(:Method, before: -> { DuckPuncher::GemInstaller.initialize! }),
12
+ Duck.new(:ActiveRecord, class: 'ActiveRecord::Base', if: -> { defined? ::ActiveRecord })
13
+ ]
14
+ end
15
+
16
+ def [](name)
17
+ list.find { |duck| duck.name == name.to_sym }
18
+ end
19
+ end
20
+
21
+ #
22
+ # Autoload our ducks
23
+ #
24
+
25
+ list.each do |duck|
26
+ autoload duck.name, duck.load_path
27
+ end
28
+ end
29
+ end
@@ -1,5 +1,3 @@
1
- require_relative 'json_storage'
2
-
3
1
  class DuckPuncher::GemInstaller
4
2
  def self.initialize!
5
3
  spec_data = DuckPuncher::JSONStorage.read('load_paths.json').values
@@ -19,7 +17,6 @@ class DuckPuncher::GemInstaller
19
17
  # @param [String] name of the gem
20
18
  # @param [String] version of the gem to install (e.g. '1.2.3')
21
19
  def perform(*args)
22
- require 'rubygems/dependency_installer'
23
20
  installer = Gem::DependencyInstaller.new(install_dir: Bundler.bundle_path.to_s, bin_dir: RbConfig::CONFIG['bindir'])
24
21
  installer.install *args.reject(&:empty?)
25
22
  installer.installed_gems.each do |gem|
@@ -1,3 +1,3 @@
1
1
  module DuckPuncher
2
- VERSION = '2.3.0'.freeze
2
+ VERSION = '2.4.0'.freeze
3
3
  end
data/lib/duck_puncher.rb CHANGED
@@ -1,24 +1,43 @@
1
1
  require 'pathname'
2
2
  require 'fileutils'
3
+ require 'logger'
3
4
  require 'duck_puncher/version'
4
5
 
5
6
  module DuckPuncher
6
- autoload :Array, 'duck_puncher/array'
7
- autoload :Numeric, 'duck_puncher/numeric'
8
- autoload :Hash, 'duck_puncher/hash'
9
- autoload :String, 'duck_puncher/string'
10
- autoload :Object, 'duck_puncher/object'
11
- autoload :Method, 'duck_puncher/method'
12
-
13
- if defined? ActiveRecord
14
- autoload :ActiveRecordExtensions, 'duck_puncher/active_record_extensions'
15
- end
7
+ autoload :JSONStorage, 'duck_puncher/json_storage'
8
+ autoload :GemInstaller, 'duck_puncher/gem_installer'
9
+ autoload :Duck, 'duck_puncher/duck'
10
+ autoload :Ducks, 'duck_puncher/ducks'
16
11
 
17
12
  def self.punch!(*names)
18
- names.each &method(:const_get)
13
+ names.each do |name|
14
+ if duck = Ducks[name]
15
+ if duck.punched?
16
+ log.info %Q(Already punched #{name})
17
+ else
18
+ log.warn %Q(Punching the #{name} ducky)
19
+ unless duck.punch
20
+ log.error %Q(Failed to punch #{name}!)
21
+ end
22
+ end
23
+ else
24
+ log.info %Q(Couldn't find "#{name}" in my list of Ducks! I know about: #{Ducks.list.map(&:name).map(&:to_s)})
25
+ end
26
+ end
27
+ nil
19
28
  end
20
29
 
21
30
  def self.punch_all!
22
- constants.each &method(:const_get)
31
+ log.warn 'Punching all ducks! Watch out!'
32
+ Ducks.list.each &:punch
33
+ end
34
+
35
+ class << self
36
+ attr_accessor :log
37
+ end
38
+
39
+ self.log = Logger.new(STDOUT).tap do |config|
40
+ config.level = Logger::INFO
41
+ config.formatter = proc { |*args| "#{args.first}: #{args.last.to_s}\n" }
23
42
  end
24
43
  end
@@ -6,4 +6,13 @@ class StringTest < MiniTest::Test
6
6
  assert_equal 'hour'.pluralize(0), 'hours'
7
7
  assert_equal 'hour'.pluralize(2), 'hours'
8
8
  end
9
+
10
+ def test_underscore
11
+ assert_equal 'MiniTest'.underscore, 'mini_test'
12
+ assert_equal 'MiniTestDoItToIt'.underscore, 'mini_test_do_it_to_it'
13
+ assert_equal 'MiniTest::Helper'.underscore, 'mini_test/helper'
14
+ assert_equal 'MiniTest::Helper::Expectations'.underscore, 'mini_test/helper/expectations'
15
+ assert_equal 'mini_test.rb', 'mini_test.rb'.underscore
16
+ assert_equal 'duck_puncher/json_storage', 'DuckPuncher::JSONStorage'.underscore
17
+ end
9
18
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: duck_puncher
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Buckley
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-05 00:00:00.000000000 Z
11
+ date: 2016-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -97,15 +97,17 @@ files:
97
97
  - bin/console
98
98
  - duck_puncher.gemspec
99
99
  - lib/duck_puncher.rb
100
- - lib/duck_puncher/active_record_extensions.rb
101
- - lib/duck_puncher/array.rb
100
+ - lib/duck_puncher/duck.rb
101
+ - lib/duck_puncher/ducks.rb
102
+ - lib/duck_puncher/ducks/active_record.rb
103
+ - lib/duck_puncher/ducks/array.rb
104
+ - lib/duck_puncher/ducks/hash.rb
105
+ - lib/duck_puncher/ducks/method.rb
106
+ - lib/duck_puncher/ducks/numeric.rb
107
+ - lib/duck_puncher/ducks/object.rb
108
+ - lib/duck_puncher/ducks/string.rb
102
109
  - lib/duck_puncher/gem_installer.rb
103
- - lib/duck_puncher/hash.rb
104
110
  - lib/duck_puncher/json_storage.rb
105
- - lib/duck_puncher/method.rb
106
- - lib/duck_puncher/numeric.rb
107
- - lib/duck_puncher/object.rb
108
- - lib/duck_puncher/string.rb
109
111
  - lib/duck_puncher/version.rb
110
112
  - test/duck_puncher/array_test.rb
111
113
  - test/duck_puncher/hash_test.rb
@@ -1,48 +0,0 @@
1
- module ActiveRecordExtensions
2
- def self.included(base)
3
- base.extend(ClassMethods)
4
- end
5
-
6
- def associations?
7
- associations.present?
8
- end
9
-
10
- def associations
11
- reflections.select { |key, _| send(key).present? rescue nil }.keys
12
- end
13
-
14
- module ClassMethods
15
- def except_for(*ids)
16
- scoped.where("#{quoted_table_name}.id NOT IN (?)", ids)
17
- end
18
-
19
- def since(time)
20
- scoped.where("#{quoted_table_name}.created_at > ?", time)
21
- end
22
-
23
- alias created_since since
24
-
25
- def before(time)
26
- scoped.where("#{quoted_table_name}.created_at < ?", time)
27
- end
28
-
29
- def updated_since(time)
30
- scoped.where("#{quoted_table_name}.updated_at > ?", time)
31
- end
32
-
33
- def between(start_at, end_at)
34
- scoped.where("#{quoted_table_name}.created_at BETWEEN ? AND ", start_at, end_at)
35
- end
36
-
37
- def latest
38
- scoped.order("#{quoted_table_name}.id ASC").last
39
- end
40
-
41
- # shim for backwards compatibility with Rails 3
42
- def scoped
43
- where(nil)
44
- end if Rails::VERSION::MAJOR != 3
45
- end
46
- end
47
-
48
- ActiveRecord::Base.send(:include, ActiveRecordExtensions)
@@ -1,18 +0,0 @@
1
- module DuckPuncher
2
- module Array
3
- def m(method_name)
4
- map(&method_name)
5
- end
6
-
7
- def mm(method_name, *args)
8
- map { |x| x.public_send(method_name, *args) }
9
- end
10
-
11
- def get(regex_or_str)
12
- regex = regex_or_str.is_a?(Regexp) ? regex_or_str : Regexp.new(Regexp.escape(regex_or_str))
13
- select { |x| x.to_s =~ regex }
14
- end
15
- end
16
- end
17
-
18
- Array.send(:include, DuckPuncher::Array)
@@ -1,25 +0,0 @@
1
- module DuckPuncher
2
- module Hash
3
- # http://coryodaniel.com/index.php/2009/12/30/ruby-getting-deeply-nested-values-from-a-hash-in-one-line-of-code/
4
- def seek(*_keys_)
5
- last_level = self
6
- sought_value = nil
7
-
8
- _keys_.each_with_index do |_key_, _idx_|
9
- if last_level.is_a?(Hash) && last_level.has_key?(_key_)
10
- if _idx_ + 1 == _keys_.length
11
- sought_value = last_level[_key_]
12
- else
13
- last_level = last_level[_key_]
14
- end
15
- else
16
- break
17
- end
18
- end
19
-
20
- sought_value
21
- end
22
- end
23
- end
24
-
25
- Hash.send(:include, DuckPuncher::Hash)
@@ -1,56 +0,0 @@
1
- module DuckPuncher
2
- module Method
3
- def to_instruct
4
- definition = Definition.new(self)
5
- RubyVM::InstructionSequence.new(definition.lines.join).disasm if definition.lines.any?
6
- end
7
-
8
- def to_source
9
- Definition.new(self).to_s
10
- end
11
-
12
- class Definition
13
- def initialize(method_handle)
14
- @file_path, @line_num = *method_handle.source_location
15
- @line_num = @line_num.to_i
16
- end
17
-
18
- # @description finds the method's source code using the indent size of the file. This means we are
19
- # restricted when it comes to parsing crappy formatted ruby files
20
- def lines
21
- return @lines if defined? @lines
22
- return [] unless @file_path
23
- @lines = []
24
- File.open(@file_path) do |f|
25
- found = false
26
- i = 0
27
- while line = f.gets and i += 1 and !found
28
- next if i < @line_num
29
- @lines << line
30
- if @indent_size
31
- found = @indent_size == find_indent_size(line)
32
- else
33
- @indent_size = find_indent_size(line)
34
- found = line.end_with?("end\n")
35
- end
36
- end
37
- end
38
- @lines
39
- end
40
-
41
- def to_s
42
- if lines.any?
43
- lines.join.gsub /^\s{#{find_indent_size(lines.first)}}/, ''
44
- else
45
- ''
46
- end
47
- end
48
-
49
- def find_indent_size(line)
50
- line[/(\s*)/].size
51
- end
52
- end
53
- end
54
- end
55
-
56
- Method.send(:include, DuckPuncher::Method)
@@ -1,51 +0,0 @@
1
- module DuckPuncher
2
- module Numeric
3
- def to_currency(prefix = '')
4
- "#{prefix}%.2f" % self.round(2)
5
- end
6
-
7
- def to_duration(seconds = false)
8
- secs = to_i
9
- mins = secs / 60
10
- hours = mins / 60
11
- buffer = ''
12
- if hours > 0
13
- num_mins = mins % 60
14
- buffer << "#{hours} h"
15
- buffer << " #{num_mins} min" unless num_mins.zero?
16
- elsif mins > 0
17
- num_secs = secs % 60
18
- buffer << "#{mins} min"
19
- buffer << " #{num_secs} s" if seconds && num_secs.nonzero?
20
- elsif seconds && secs >= 0
21
- buffer << "#{secs} s"
22
- end
23
- buffer
24
- end
25
-
26
- # similar to Rails' #time_ago_in_words
27
- def to_time_ago
28
- secs = to_i
29
- mins = secs / 60
30
- hours = mins / 60
31
- days = hours / 24
32
- buffer = ''
33
- if days > 0
34
- buffer << "#{days} #{'day'.pluralize(days)}"
35
- elsif hours > 0
36
- buffer << "#{hours} #{'hour'.pluralize(hours)}"
37
- elsif mins > 0
38
- buffer << "#{mins} #{'minute'.pluralize(mins)}"
39
- elsif secs >= 0
40
- buffer << "less than a minute"
41
- end
42
- buffer << ' ago'
43
- end
44
-
45
- def to_rad
46
- self / 180 * Math::PI
47
- end
48
- end
49
- end
50
-
51
- Numeric.send(:include, DuckPuncher::Numeric)
@@ -1,19 +0,0 @@
1
- require_relative 'json_storage'
2
- require_relative 'gem_installer'
3
-
4
- module DuckPuncher
5
- module Object
6
- def clone!
7
- Marshal.load Marshal.dump self
8
- end unless defined? clone!
9
-
10
- def require!(file_or_gem, version = '')
11
- if DuckPuncher::GemInstaller.new.perform(file_or_gem, version)
12
- require file_or_gem.tr('-', '/')
13
- end
14
- end
15
- end
16
- end
17
-
18
- DuckPuncher::GemInstaller.initialize!
19
- Object.send(:include, DuckPuncher::Object)
@@ -1,9 +0,0 @@
1
- module DuckPuncher
2
- module String
3
- def pluralize(count)
4
- "#{self}#{'s' if count != 1}"
5
- end
6
- end
7
- end
8
-
9
- String.send(:include, DuckPuncher::String)