putter 0.2.1 → 0.3.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: c10cb5a65a0e9af1fecc76056ebf982133198a53
4
- data.tar.gz: 6f56fba3228d58b36946c070dadf48710ec36cd2
3
+ metadata.gz: 7b61e558de7dab6687ddc1e44fcb1a66ae6a4669
4
+ data.tar.gz: 23a571a29ea9c44223a86e9762d02d5eb13d7352
5
5
  SHA512:
6
- metadata.gz: 13583a279674f58f63f03d084e3bb9b9d974b359f30ede539c7ae1d564999d1832b9a7317d5abff091dfb5e5115af81e0f6552c5cc2cbd2cb58458a82c61e284
7
- data.tar.gz: 3cce9ec1a107a16c235c642af2a01b8d0c5da3f7972fd702d61d48388aa3e1e29952c10f54cab08003a3d1a26397aca8f9162993c870848e78d8c58d30a035d1
6
+ metadata.gz: b700661ef9567e2e9f5b19880a491f0e37f7b7fd32597e024a04c0fd18df13bf5147add15a3dc49956a92850e0eb31df52eb13b1c89d0e31d03e00978f59b5d8
7
+ data.tar.gz: a5c554a5f52c2181a8d39cedfbeb50950a4b3d5420c1f99cf453f08797edd4b44e25a8d307f36d1265c18d3aab53b9f30290460c2e4cd28df913bfead72d3915
data/CHANGELOG.md CHANGED
@@ -1,4 +1,6 @@
1
1
  # CHANGELOG
2
+ ### 0.3.0 - 2016-07-08
3
+ - Add `Putter.watch` ability to watch a class and instances created by that class
2
4
 
3
5
  ### 0.2.1 - 2016-06-08
4
6
  - Add missing Gemfile.lock to bundled gem.
data/README.md CHANGED
@@ -24,9 +24,15 @@ Or install it yourself as:
24
24
 
25
25
  ## Usage
26
26
 
27
+ There are two ways to use putter. `Putter.follow` and `Putter.watch`.
28
+
27
29
  ### Putter.follow
28
30
 
29
- Currently there is only one use for Putter, the `follow` method.
31
+ `Putter.follow` will allow you to create a wrapper around an object and then you can pass that wrapped object around. The advantage to using follow is that if a method is called that doesn't exist, or a method is created at runtime, the wrapped object will intercept those calls. This works on both instances and classes. However, following a class will not result in created instances of that class being followed.
32
+
33
+ Additionally, following an object will not allow you to intercept calls to a class that occurred outside the wrapped object. For that functionality, use `Putter.watch`
34
+
35
+ `Putter.follow` usage:
30
36
 
31
37
  ```ruby
32
38
  class MyObject
@@ -48,7 +54,7 @@ Service.do_stuff(object)
48
54
  Will output:
49
55
 
50
56
  ```bash
51
- Putter Debugging: Object instance -- Method: :hello, Args: [:world, "!"], Result: "Hello world!"
57
+ Putter Debugging: Object instance ./putter/README.md:57 -- Method: :hello, Args: [:world, "!"], Result: "Hello world!"
52
58
  ```
53
59
 
54
60
  #### `Putter.follow` Options
@@ -61,18 +67,58 @@ Putter.follow(
61
67
  )
62
68
  ```
63
69
 
70
+ ### Putter.watch
71
+
72
+ `Putter.watch` can be used on classes to follow created instances of the class or to intercept method calls that occur throughout your application.
73
+
74
+ `Putter.follow` usage:
75
+
76
+ ```ruby
77
+ class MyObject
78
+ def self.hello_class(arg, punc)
79
+ "The class says hello #{arg.to_s}#{punc}"
80
+ end
81
+
82
+ def hello_instance(arg, punc)
83
+ "An instance says hello #{arg.to_s}#{punc}"
84
+ end
85
+ end
86
+
87
+ Putter.watch(MyObject)
88
+ MyObject.hello_class("world", "!")
89
+ my_obj = MyObject.new
90
+ my_obj.hello_instance("world", "!")
91
+ ```
92
+
93
+ Will output:
94
+
95
+ ```bash
96
+ Putter Debugging: Object ./putter/README.md:96 -- Method: :hello_class, Args: [:world, "!"], Result: "The class says hello world!"
97
+ Putter Debugging: Object instance 1 ./putter/README.md:97 -- Method: :hello_instance, Args: [:world, "!"], Result: "The instance says hello world!"
98
+ ```
99
+
100
+ #### `Putter.follow` Options
101
+
102
+ ```ruby
103
+ Putter.watch(
104
+ ClassToFollow,
105
+ label: "My object", # Label to use after "Putter Debugging: My object". Will be "ClassName" for classes or "ClassName instance #" for instances
106
+ )
107
+ ```
108
+
64
109
  ## Configuration
65
110
 
66
111
  Putter currently has 3 configuration options:
67
112
 
68
113
  ```ruby
69
114
  Putter.configure do |config|
70
- # 'print_strategy' takes a block that receives four arguments with the label, method, args array,
71
- # and result respectively. This block will be used after each method is called, it must contain
72
- # puts or logger calls, to print or any other method callbacks that are helpful.
115
+ # 'print_strategy' takes a block that receives five arguments with the label, line,
116
+ # method, args array, and result respectively. This block will be used after each method
117
+ # is called, it must contain puts or logger calls, to print or any other method callbacks
118
+ # that are helpful.
73
119
  # Defaults to Putter::PrintStrategy::Default
74
- config.print_strategy = Proc.new do |label, method, args, result|
75
- puts "Label: #{label}, Method: #{method}, Args: #{args}, Result: #{result}"
120
+ config.print_strategy = Proc.new do |label, line, method, args, result|
121
+ puts "#{line} - Label: #{label}, Method: #{method}, Args: #{args}, Result: #{result}"
76
122
  end
77
123
 
78
124
  # 'ignore_methods_from' takes an array of class names and will ignore both class and instance methods
@@ -90,7 +136,6 @@ end
90
136
  ## Planned Features
91
137
  Feel free to open a PR to implement any of these if they are not yet added:
92
138
 
93
- - Ability to watch any instance of a class calling a method
94
139
  - Active Record specific printing
95
140
  - Checking Rails.env to double check that putter is not called in production
96
141
 
@@ -1,5 +1,7 @@
1
1
  module Putter
2
2
  class Follower < BasicObject
3
+ include MethodCreator
4
+
3
5
  attr_reader :object, :proxied_methods, :proxy
4
6
 
5
7
  def initialize(obj, options={})
@@ -26,14 +28,9 @@ module Putter
26
28
  end
27
29
 
28
30
  def add_method(method)
29
- @proxy.instance_exec(@label) do |label, print_results|
30
- define_method(method) do |*proxy_args, &blk|
31
- args_string = proxy_args.to_s
32
- result = super *proxy_args, &blk
33
- ::Putter.configuration.print_strategy.call label, method, args_string, result
34
- result
35
- end
36
- end
31
+ data = ProxyMethodData.new(method, @label)
32
+
33
+ add_putter_method_to_proxy(@proxy, :instance_exec, data)
37
34
  end
38
35
 
39
36
  def _add_method?(method)
@@ -0,0 +1,11 @@
1
+ module Putter
2
+ module InstanceFollower
3
+ @@putter_followed_instances = []
4
+
5
+ def new(*args, &blk)
6
+ result = super *args, &blk
7
+ @@putter_followed_instances << result
8
+ ::Putter.follow(result, label: "#{name} instance #{@@putter_followed_instances.count}")
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module Putter
2
+ module MethodCreator
3
+ def add_putter_method_to_proxy(proxy, eval_method, data)
4
+ proxy.send(eval_method, data) do |data|
5
+ define_method(data.method) do |*proxy_args, &blk|
6
+ line = caller.find {|call| call.match(data.stack_trace_ignore_regex)}
7
+ line = line.split(::Dir.pwd)[1]
8
+ args_string = proxy_args.to_s
9
+ result = super *proxy_args, &blk
10
+ ::Putter.configuration.print_strategy.call data.label, line, data.method, args_string, result
11
+ result
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -2,10 +2,11 @@ require "colorize"
2
2
 
3
3
  module Putter
4
4
  module PrintStrategy
5
- Default = Proc.new do |label, method, args, result|
6
- prefix = "\tPutter Debugging: ".colorize(:cyan)
7
- suffix = "#{label} -- Method: :#{method}, Args: #{args}, Result: #{result}".colorize(:green)
8
- puts prefix + suffix
5
+ Default = Proc.new do |label, line, method, args, result|
6
+ prefix = "\tPutter Debugging: #{label} ".colorize(:cyan)
7
+ line = !line.nil? ? ".#{line} " : " "
8
+ suffix = "-- Method: :#{method}, Args: #{args}, Result: #{result}".colorize(:green)
9
+ puts prefix + line + suffix
9
10
  end
10
11
  end
11
12
  end
@@ -0,0 +1,16 @@
1
+ module Putter
2
+ class ProxyMethodData
3
+ STACK_TRACE_IGNORE_REGEX = /(?!.*(\.rbenv|\.rvm|\/lib\/putter\/follower))(^.*$)/
4
+
5
+ attr_reader :method, :label
6
+
7
+ def initialize(method, label)
8
+ @method = method
9
+ @label = label
10
+ end
11
+
12
+ def stack_trace_ignore_regex
13
+ STACK_TRACE_IGNORE_REGEX
14
+ end
15
+ end
16
+ end
@@ -1,3 +1,3 @@
1
1
  module Putter
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -0,0 +1,53 @@
1
+ module Putter
2
+ class Watcher
3
+ extend MethodCreator
4
+
5
+ @label = ""
6
+
7
+ def self.watch(obj, options={})
8
+ _set_label(options[:label], obj.name)
9
+
10
+ class << obj
11
+ prepend InstanceFollower
12
+ prepend Putter::Watcher.class_proxy(self)
13
+ end
14
+ end
15
+
16
+ def self.class_proxy(klass)
17
+ proxy = MethodProxy.new
18
+
19
+ methods_to_proxy(klass).each do |method|
20
+ data = ProxyMethodData.new(method, label)
21
+ add_putter_method_to_proxy(proxy, :module_exec, data)
22
+ end
23
+
24
+ proxy
25
+ end
26
+
27
+ def self.methods_to_proxy(klass)
28
+ ignored_methods = []
29
+
30
+ Putter.configuration.ignore_methods_from.each do |klass|
31
+ ignored_methods += klass.methods
32
+ end
33
+
34
+ klass.instance_methods - ignored_methods + Putter.configuration.methods_whitelist.map(&:to_sym) + [:new]
35
+ end
36
+
37
+ def self.label
38
+ @label
39
+ end
40
+
41
+ def self.label=(label)
42
+ @label = label
43
+ end
44
+
45
+ def self._set_label(label, class_name)
46
+ if !label.nil? && label != ""
47
+ @label = label
48
+ else
49
+ @label = class_name
50
+ end
51
+ end
52
+ end
53
+ end
data/lib/putter.rb CHANGED
@@ -1,10 +1,15 @@
1
1
  require "putter/configuration"
2
2
  require "putter/errors"
3
- require "putter/follower"
3
+ require "putter/instance_follower"
4
+ require "putter/method_creator"
4
5
  require "putter/method_proxy"
5
6
  require "putter/print_strategy"
7
+ require "putter/proxy_method_data"
6
8
  require "putter/version"
7
9
 
10
+ require "putter/follower"
11
+ require "putter/watcher"
12
+
8
13
  module Putter
9
14
  include Errors
10
15
 
@@ -16,6 +21,10 @@ module Putter
16
21
  Putter::Follower.new(obj, options)
17
22
  end
18
23
 
24
+ def self.watch(obj, options={})
25
+ Putter::Watcher.watch(obj, options)
26
+ end
27
+
19
28
  def self.configuration
20
29
  @configuration ||= Configuration.new
21
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: putter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John DeWyze
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-08 00:00:00.000000000 Z
11
+ date: 2016-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -109,9 +109,13 @@ files:
109
109
  - lib/putter/configuration.rb
110
110
  - lib/putter/errors.rb
111
111
  - lib/putter/follower.rb
112
+ - lib/putter/instance_follower.rb
113
+ - lib/putter/method_creator.rb
112
114
  - lib/putter/method_proxy.rb
113
115
  - lib/putter/print_strategy.rb
116
+ - lib/putter/proxy_method_data.rb
114
117
  - lib/putter/version.rb
118
+ - lib/putter/watcher.rb
115
119
  - putter.gemspec
116
120
  homepage: https://github.com/dewyze/putter
117
121
  licenses: