duck_puncher 2.3.0 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +33 -24
- data/bin/console +1 -0
- data/lib/duck_puncher/duck.rb +30 -0
- data/lib/duck_puncher/ducks/active_record.rb +48 -0
- data/lib/duck_puncher/ducks/array.rb +18 -0
- data/lib/duck_puncher/ducks/hash.rb +25 -0
- data/lib/duck_puncher/ducks/method.rb +56 -0
- data/lib/duck_puncher/ducks/numeric.rb +51 -0
- data/lib/duck_puncher/ducks/object.rb +15 -0
- data/lib/duck_puncher/ducks/string.rb +13 -0
- data/lib/duck_puncher/ducks.rb +29 -0
- data/lib/duck_puncher/gem_installer.rb +0 -3
- data/lib/duck_puncher/version.rb +1 -1
- data/lib/duck_puncher.rb +31 -12
- data/test/duck_puncher/string_test.rb +9 -0
- metadata +11 -9
- data/lib/duck_puncher/active_record_extensions.rb +0 -48
- data/lib/duck_puncher/array.rb +0 -18
- data/lib/duck_puncher/hash.rb +0 -25
- data/lib/duck_puncher/method.rb +0 -56
- data/lib/duck_puncher/numeric.rb +0 -51
- data/lib/duck_puncher/object.rb +0 -19
- data/lib/duck_puncher/string.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d30be8964065fb57d3de53e4e23b2deaf8ceb277
|
4
|
+
data.tar.gz: f2bc471c1a31a1f438680f21440b86d489092cd1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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)`
|
6
|
-
Array#mm => `[].mm(:sub, /[aeiou]/, '*')`
|
7
|
-
Array#get => `[].methods.get('ty?')`
|
8
|
-
Hash#seek => `{a: 1, b: {c: 2}}.seek(:b, :c)`
|
9
|
-
Numeric#to_currency => `25.245.to_currency`
|
10
|
-
Numeric#to_duration => `10_000.to_duration`
|
11
|
-
Numeric#to_time_ago => `10_000.to_time_ago`
|
12
|
-
Numeric#to_rad => `10.15.to_rad`
|
13
|
-
String#pluralize => `'hour'.pluralize(2)`
|
14
|
-
|
15
|
-
Object#
|
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
@@ -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|
|
data/lib/duck_puncher/version.rb
CHANGED
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 :
|
7
|
-
autoload :
|
8
|
-
autoload :
|
9
|
-
autoload :
|
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
|
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
|
-
|
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.
|
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-
|
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/
|
101
|
-
- lib/duck_puncher/
|
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)
|
data/lib/duck_puncher/array.rb
DELETED
@@ -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)
|
data/lib/duck_puncher/hash.rb
DELETED
@@ -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)
|
data/lib/duck_puncher/method.rb
DELETED
@@ -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)
|
data/lib/duck_puncher/numeric.rb
DELETED
@@ -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)
|
data/lib/duck_puncher/object.rb
DELETED
@@ -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)
|