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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d3f3e8e62629faa8e0e9a59e754a21255648533e
4
- data.tar.gz: d39ba33cd952bd2dbf57cb1281169d3480696f10
3
+ metadata.gz: 6a46a207adebfd5c36e0f4d5dc51e9dd3b02d5a5
4
+ data.tar.gz: ad067c6ed3a67e38f95ff2185d51fffe2a9c11d2
5
5
  SHA512:
6
- metadata.gz: 0d52cce59da693d390269f0398266ef5c84840bcac9f7fad3082c1e80b987a766621b3a45b51e16c7cccbdcd0505940d7c1706067e1747eac95bfb3a4a6c79b9
7
- data.tar.gz: 9f4316045b90d20dd0ae18b4c05c7742d51576e077efd028f8175cc510fd532fddf87548c1aa0c8f37168df84d33a7628c85317afa51be200c66044834bc345d
6
+ metadata.gz: 61703bbb58544430f7bfe069abd9f4433d5c886d835864c1bcdbe0bcd6f889a33421cd91e0c0193e11640fd3fb93fb8b38b088d5521c0d1db4a7e5c69f29017e
7
+ data.tar.gz: 7b2d75382bbd9a1395da6736023077e95691d3a5df02f6129b918eca944f1ddafbce4a3ec7e92cf1a64ca94a9a7e6e05757b7accee1e9ea941d7bbca60839f60
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ .duck_puncher/
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.2.1
5
+ - 2.2.2
6
+ - 2.2.3
7
+ before_install: gem install bundler -v 1.10.5
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,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'pp'
5
+ require 'duck_puncher'
6
+ require 'irb'
7
+
8
+ DuckPuncher.punch_all!
9
+
10
+ IRB.start
@@ -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)
@@ -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)
@@ -1,3 +1,3 @@
1
1
  module DuckPuncher
2
- VERSION = '2.1.0'.freeze
2
+ VERSION = '2.2.0'.freeze
3
3
  end
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
@@ -0,0 +1,7 @@
1
+ class Wut
2
+ def to_a
3
+ ['w'] + ['u'] + ['t']
4
+ end
5
+
6
+ def to_f() Float::INFINITY end
7
+ 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.1.0
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-09-26 00:00:00.000000000 Z
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