duck_puncher 2.1.0 → 2.2.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 +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +7 -0
- data/README.md +23 -0
- data/bin/console +10 -0
- data/lib/duck_puncher/gem_installer.rb +35 -0
- data/lib/duck_puncher/json_storage.rb +28 -0
- data/lib/duck_puncher/method.rb +44 -0
- data/lib/duck_puncher/object.rb +10 -0
- data/lib/duck_puncher/version.rb +1 -1
- data/lib/duck_puncher.rb +3 -0
- data/test/duck_puncher/method_test.rb +30 -0
- data/test/fixtures/wut.rb +7 -0
- metadata +13 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a46a207adebfd5c36e0f4d5dc51e9dd3b02d5a5
|
4
|
+
data.tar.gz: ad067c6ed3a67e38f95ff2185d51fffe2a9c11d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61703bbb58544430f7bfe069abd9f4433d5c886d835864c1bcdbe0bcd6f889a33421cd91e0c0193e11640fd3fb93fb8b38b088d5521c0d1db4a7e5c69f29017e
|
7
|
+
data.tar.gz: 7b2d75382bbd9a1395da6736023077e95691d3a5df02f6129b918eca944f1ddafbce4a3ec7e92cf1a64ca94a9a7e6e05757b7accee1e9ea941d7bbca60839f60
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -12,6 +12,22 @@ These are the ducks I can punch:
|
|
12
12
|
Numeric#to_rad => `10.15.to_rad` returns 0.17715091907742445
|
13
13
|
String#pluralize => `'hour'.pluralize(2)` turns "hour" into "hours"
|
14
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)>
|
29
|
+
Method#to_instruct => `Benchmark.method(:measure).to_instruct` returns the Ruby VM instruction sequence for the method
|
30
|
+
|
15
31
|
|
16
32
|
## Install
|
17
33
|
|
@@ -25,3 +41,10 @@ Ducks need to be _loaded_ before they can be punched! Maybe do this in an initia
|
|
25
41
|
DuckPuncher.punch! :Hash, :Object #=> only punches the specified ducks
|
26
42
|
DuckPuncher.punch_all! #=> punches all the ducks
|
27
43
|
```
|
44
|
+
|
45
|
+
## Contributing
|
46
|
+
|
47
|
+
* Fork it
|
48
|
+
* Run tests with `rake`
|
49
|
+
* Start an IRB console that already has all your ducks in a row `bin/console`
|
50
|
+
* Make changes and submit a PR to [https://github.com/ridiculous/duck_puncher](https://github.com/ridiculous/duck_puncher)
|
data/bin/console
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative 'json_storage'
|
2
|
+
|
3
|
+
class DuckPuncher::GemInstaller
|
4
|
+
def self.initialize!
|
5
|
+
spec_data = DuckPuncher::JSONStorage.read('load_paths.json').values
|
6
|
+
spec_data.each do |spec|
|
7
|
+
spec[:load_paths].each do |load_path|
|
8
|
+
next if $LOAD_PATH.include? load_path
|
9
|
+
$LOAD_PATH.unshift load_path
|
10
|
+
end
|
11
|
+
begin
|
12
|
+
require spec[:require_with]
|
13
|
+
rescue LoadError => e
|
14
|
+
puts "Failed to require #{spec[:require_with]}. #{e.inspect}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param [String] name of the gem
|
20
|
+
# @param [String] version of the gem to install (e.g. '1.2.3')
|
21
|
+
def perform(*args)
|
22
|
+
require 'rubygems/dependency_installer'
|
23
|
+
installer = Gem::DependencyInstaller.new(install_dir: Bundler.bundle_path.to_s, bin_dir: RbConfig::CONFIG['bindir'])
|
24
|
+
installer.install *args.reject(&:empty?)
|
25
|
+
installer.installed_gems.each do |gem|
|
26
|
+
full_load_path = Bundler.bundle_path.join('gems', "#{gem.name}-#{gem.version}", "lib")
|
27
|
+
next if $LOAD_PATH.include?(full_load_path.to_s)
|
28
|
+
$LOAD_PATH.unshift full_load_path.to_s
|
29
|
+
DuckPuncher::JSONStorage.write 'load_paths.json', args.first, full_load_path
|
30
|
+
end
|
31
|
+
installer.installed_gems.any?
|
32
|
+
rescue => e
|
33
|
+
puts "Failed to install #{args.first}. #{e.inspect}"
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module DuckPuncher
|
2
|
+
module JSONStorage
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
def self.dir_name
|
6
|
+
Pathname.new('.duck_puncher')
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.write(file_name, key, load_path)
|
10
|
+
FileUtils.mkdir(dir_name) unless File.exists?(dir_name)
|
11
|
+
data = read(file_name)
|
12
|
+
key = key.to_sym
|
13
|
+
data[key] ||= {}
|
14
|
+
data[key][:require_with] ||= key.to_s.tr('-', '/')
|
15
|
+
data[key][:load_paths] ||= []
|
16
|
+
data[key][:load_paths] << load_path.to_s unless data[key][:load_paths].include?(load_path.to_s)
|
17
|
+
File.open(dir_name.join(file_name), 'wb') { |f| f << data.to_json }
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.read(file_name)
|
21
|
+
if File.exists?(dir_name.join file_name)
|
22
|
+
JSON.parse File.read(dir_name.join file_name), symbolize_names: true
|
23
|
+
else
|
24
|
+
{}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,44 @@
|
|
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
|
+
class Definition
|
9
|
+
def initialize(method_handle)
|
10
|
+
@file_path, @line_num = *method_handle.source_location
|
11
|
+
@line_num = @line_num.to_i
|
12
|
+
end
|
13
|
+
|
14
|
+
# @description finds the method's source code using the indent size of the file. This means we are
|
15
|
+
# restricted when it comes to parsing crappy formatted ruby files
|
16
|
+
def lines
|
17
|
+
return @lines if defined? @lines
|
18
|
+
return [] unless @file_path
|
19
|
+
@lines = []
|
20
|
+
File.open(@file_path) do |f|
|
21
|
+
found = false
|
22
|
+
i = 0
|
23
|
+
while line = f.gets and i += 1 and !found
|
24
|
+
next if i < @line_num
|
25
|
+
@lines << line
|
26
|
+
if @indent_size
|
27
|
+
found = @indent_size == find_indent_size(line)
|
28
|
+
else
|
29
|
+
@indent_size = find_indent_size(line)
|
30
|
+
found = line.end_with?("end\n")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
@lines
|
35
|
+
end
|
36
|
+
|
37
|
+
def find_indent_size(line)
|
38
|
+
line[/(\s*)/].size
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
Method.send(:include, DuckPuncher::Method)
|
data/lib/duck_puncher/object.rb
CHANGED
@@ -1,9 +1,19 @@
|
|
1
|
+
require_relative 'json_storage'
|
2
|
+
require_relative 'gem_installer'
|
3
|
+
|
1
4
|
module DuckPuncher
|
2
5
|
module Object
|
3
6
|
def clone!
|
4
7
|
Marshal.load Marshal.dump self
|
5
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
|
6
15
|
end
|
7
16
|
end
|
8
17
|
|
18
|
+
DuckPuncher::GemInstaller.initialize!
|
9
19
|
Object.send(:include, DuckPuncher::Object)
|
data/lib/duck_puncher/version.rb
CHANGED
data/lib/duck_puncher.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'fileutils'
|
1
3
|
require 'duck_puncher/version'
|
2
4
|
|
3
5
|
module DuckPuncher
|
@@ -6,6 +8,7 @@ module DuckPuncher
|
|
6
8
|
autoload :Hash, 'duck_puncher/hash'
|
7
9
|
autoload :String, 'duck_puncher/string'
|
8
10
|
autoload :Object, 'duck_puncher/object'
|
11
|
+
autoload :Method, 'duck_puncher/method'
|
9
12
|
|
10
13
|
if defined? ActiveRecord
|
11
14
|
autoload :ActiveRecordExtensions, 'duck_puncher/active_record_extensions'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
require_relative '../fixtures/wut'
|
3
|
+
|
4
|
+
class MethodTest < MiniTest::Test
|
5
|
+
|
6
|
+
# Called before every test method runs. Can be used
|
7
|
+
# to set up fixture information.
|
8
|
+
def setup
|
9
|
+
@subject = Wut.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# Called after every test method runs. Can be used to tear
|
13
|
+
# down fixture information.
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
# Do nothing
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_to_instruct
|
20
|
+
assert_match /RubyVM::InstructionSequence:to_a/, @subject.method(:to_a).to_instruct
|
21
|
+
assert_match /newarray/, @subject.method(:to_a).to_instruct
|
22
|
+
assert_match /opt_plus/, @subject.method(:to_a).to_instruct
|
23
|
+
assert_equal nil, [].method(:to_s).to_instruct
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_to_instruct_single_line
|
27
|
+
assert_match /RubyVM::InstructionSequence:to_f/, @subject.method(:to_f).to_instruct
|
28
|
+
assert_match /getconstant\s*:INFINITY/, @subject.method(:to_f).to_instruct
|
29
|
+
end
|
30
|
+
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.2.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: 2015-
|
11
|
+
date: 2015-12-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -81,31 +81,39 @@ dependencies:
|
|
81
81
|
description: Duck punches Ruby with some of my favorite class extensions
|
82
82
|
email:
|
83
83
|
- arebuckley@gmail.com
|
84
|
-
executables:
|
84
|
+
executables:
|
85
|
+
- console
|
85
86
|
extensions: []
|
86
87
|
extra_rdoc_files: []
|
87
88
|
files:
|
88
89
|
- ".gitignore"
|
89
90
|
- ".ruby-gemset"
|
90
91
|
- ".ruby-version"
|
92
|
+
- ".travis.yml"
|
91
93
|
- Gemfile
|
92
94
|
- LICENSE.txt
|
93
95
|
- README.md
|
94
96
|
- Rakefile
|
97
|
+
- bin/console
|
95
98
|
- duck_puncher.gemspec
|
96
99
|
- lib/duck_puncher.rb
|
97
100
|
- lib/duck_puncher/active_record_extensions.rb
|
98
101
|
- lib/duck_puncher/array.rb
|
102
|
+
- lib/duck_puncher/gem_installer.rb
|
99
103
|
- lib/duck_puncher/hash.rb
|
104
|
+
- lib/duck_puncher/json_storage.rb
|
105
|
+
- lib/duck_puncher/method.rb
|
100
106
|
- lib/duck_puncher/numeric.rb
|
101
107
|
- lib/duck_puncher/object.rb
|
102
108
|
- lib/duck_puncher/string.rb
|
103
109
|
- lib/duck_puncher/version.rb
|
104
110
|
- test/duck_puncher/array_test.rb
|
105
111
|
- test/duck_puncher/hash_test.rb
|
112
|
+
- test/duck_puncher/method_test.rb
|
106
113
|
- test/duck_puncher/numeric_test.rb
|
107
114
|
- test/duck_puncher/object_test.rb
|
108
115
|
- test/duck_puncher/string_test.rb
|
116
|
+
- test/fixtures/wut.rb
|
109
117
|
- test/test_helper.rb
|
110
118
|
homepage: https://github.com/ridiculous/duck_puncher
|
111
119
|
licenses:
|
@@ -134,7 +142,9 @@ summary: Duck punches Ruby
|
|
134
142
|
test_files:
|
135
143
|
- test/duck_puncher/array_test.rb
|
136
144
|
- test/duck_puncher/hash_test.rb
|
145
|
+
- test/duck_puncher/method_test.rb
|
137
146
|
- test/duck_puncher/numeric_test.rb
|
138
147
|
- test/duck_puncher/object_test.rb
|
139
148
|
- test/duck_puncher/string_test.rb
|
149
|
+
- test/fixtures/wut.rb
|
140
150
|
- test/test_helper.rb
|