putter 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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: