object_tracker 1.0.5 → 1.1.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/README.md +203 -45
- data/lib/object_tracker.rb +6 -2
- data/lib/object_tracker/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bfd7b109271fd7711dc44cd0d4e0470ca476d405
|
4
|
+
data.tar.gz: becc3082a28a2f1eb0ee73f4a727f58e07a1d1c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 102d330f30f4a7952ecd06f2c1a0967a1ff67277053b69b51006bcd86b9b3a40a215de08cd235a8b542bec4d6f69b4cf920b8bc325541e3ffc3603d96dbdd281
|
7
|
+
data.tar.gz: a92c6e9d0fa2e2635bcb91cf5377b64c5c29956ed11f9853a0acab61e83393ee790a92c3f8ee499056e3245037d96ed0278525421668f0afd99821457eeba559
|
data/README.md
CHANGED
@@ -1,6 +1,11 @@
|
|
1
|
-
# ObjectTracker
|
1
|
+
# Ruby ObjectTracker
|
2
2
|
|
3
|
-
Track
|
3
|
+
Track class and instance methods, including arguments and definition source. You can extend a class to track calls to itself and it's
|
4
|
+
instances, or extend instances directly. This can be helpful for debugging by providing info on what methods are being called on your object
|
5
|
+
|
6
|
+
## Requirements
|
7
|
+
|
8
|
+
* Ruby 2+
|
4
9
|
|
5
10
|
## Installation
|
6
11
|
|
@@ -10,79 +15,232 @@ Add this line to your application's Gemfile:
|
|
10
15
|
gem 'object_tracker'
|
11
16
|
```
|
12
17
|
|
13
|
-
|
14
|
-
|
15
|
-
$ bundle
|
18
|
+
Or try it out by cloning the repo and running:
|
16
19
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
+
```bash
|
21
|
+
irb -I ./lib -r object_tracker
|
22
|
+
```
|
20
23
|
|
21
24
|
## Usage
|
22
25
|
|
23
26
|
```ruby
|
24
|
-
class
|
27
|
+
class MyKlass
|
25
28
|
extend ObjectTracker
|
26
29
|
|
27
30
|
def fetch(name)
|
28
|
-
"Fetch the ball #{name}!"
|
31
|
+
"Fetch the ball, #{name}!"
|
29
32
|
end
|
30
33
|
end
|
34
|
+
```
|
35
|
+
|
36
|
+
Track a single method:
|
31
37
|
|
32
|
-
|
33
|
-
|
34
|
-
* called "#inspect" [RUBY CORE]
|
35
|
-
#=> Dog
|
36
|
-
Dog.new.fetch('Hudog')
|
37
|
-
* called ".new" [RUBY CORE]
|
38
|
-
* called "#fetch" with Hudog [(irb):4]
|
39
|
-
#=> Fetch the ball Hudog!
|
38
|
+
```ruby
|
39
|
+
MyKlass.track :fetch
|
40
40
|
```
|
41
41
|
|
42
|
-
Or
|
42
|
+
Or track all methods:
|
43
43
|
|
44
44
|
```ruby
|
45
|
-
|
45
|
+
MyKlass.track_all!
|
46
46
|
```
|
47
47
|
|
48
|
-
Or track
|
48
|
+
Or track an instance:
|
49
49
|
|
50
50
|
```ruby
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
end
|
55
|
-
end
|
51
|
+
obj = MyKlass.new.extend ObjectTracker
|
52
|
+
obj.track_all!
|
53
|
+
```
|
56
54
|
|
57
|
-
|
58
|
-
|
59
|
-
a
|
55
|
+
## Example
|
56
|
+
|
57
|
+
Tracking a Sequel::Model object:
|
58
|
+
|
59
|
+
```bash
|
60
|
+
>> Website.extend ObjectTracker
|
61
|
+
=> Website
|
62
|
+
>> Website.track_all!
|
63
|
+
* called "#inspect" [sequel-4.21.0/lib/sequel/model/base.rb:1368]
|
64
|
+
=> Website
|
65
|
+
>> Website.count
|
66
|
+
* called ".count" [sequel-4.21.0/lib/sequel/model/plugins.rb:28]
|
67
|
+
* called ".dataset" [sequel-4.21.0/lib/sequel/model/base.rb:157]
|
68
|
+
I, [2015-07-07T19:15:57.897695 #39091] INFO -- : (0.000794s) SELECT count(*) AS "count" FROM "websites" LIMIT 1
|
69
|
+
=> 0
|
70
|
+
>> Website.first
|
71
|
+
* called ".first" [sequel-4.21.0/lib/sequel/model/base.rb:459]
|
72
|
+
* called ".dataset" [sequel-4.21.0/lib/sequel/model/base.rb:157]
|
73
|
+
I, [2015-07-07T19:16:01.016948 #39091] INFO -- : (0.001045s) SELECT * FROM "websites" LIMIT 1
|
74
|
+
=> nil
|
75
|
+
>> Website.create(user_id: 101, url: 'http://cnn.com')
|
76
|
+
* called ".create" with {:user_id=>101, :url=>"http://cnn.com"} [sequel-4.21.0/lib/sequel/model/base.rb:147]
|
77
|
+
* called ".new" with {:user_id=>101, :url=>"http://cnn.com"} [RUBY CORE]
|
78
|
+
* called "#set" with {:user_id=>101, :url=>"http://cnn.com"} [sequel-4.21.0/lib/sequel/model/base.rb:1572]
|
79
|
+
* called ".setter_methods" with default [sequel-4.21.0/lib/sequel/model/base.rb:732]
|
80
|
+
* called "#model" [RUBY CORE]
|
81
|
+
* called ".setter_methods" [sequel-4.21.0/lib/sequel/model/base.rb:732]
|
82
|
+
* called ".allowed_columns" [sequel-4.21.0/lib/sequel/model/base.rb:13]
|
83
|
+
* called ".instance_methods" [RUBY CORE]
|
84
|
+
* called "#primary_key" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
85
|
+
* called ".restrict_primary_key?" [sequel-4.21.0/lib/sequel/model/base.rb:646]
|
86
|
+
* called "#primary_key" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
87
|
+
* called "#strict_param_setting" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
88
|
+
* called "#frozen?" [RUBY CORE]
|
89
|
+
* called "#strict_param_setting" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
90
|
+
* called "#set_column_value" with user_id=, 101 [RUBY CORE]
|
91
|
+
* called "#user_id=" with 101 [sequel-4.21.0/lib/sequel/model/base.rb:858]
|
92
|
+
* called "#typecast_on_assignment" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
93
|
+
* called "#frozen?" [RUBY CORE]
|
94
|
+
* called "#typecast_on_assignment" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
95
|
+
* called "#db_schema" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
96
|
+
* called "#db_schema" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
97
|
+
* called "#db_schema" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
98
|
+
* called "#db_schema" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
99
|
+
* called "#raise_on_typecast_failure" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
100
|
+
* called "#frozen?" [RUBY CORE]
|
101
|
+
* called "#raise_on_typecast_failure" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
102
|
+
* called "#model" [RUBY CORE]
|
103
|
+
* called "#db" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
104
|
+
* called "#new?" [sequel-4.21.0/lib/sequel/model/base.rb:1454]
|
105
|
+
* called "#model" [RUBY CORE]
|
106
|
+
* called ".autoreloading_associations" [sequel-4.21.0/lib/sequel/model/associations.rb:1417]
|
107
|
+
* called "#changed_columns" [sequel-4.21.0/lib/sequel/model/base.rb:1252]
|
108
|
+
* called "#set_column_value" with url=, http://cnn.com [RUBY CORE]
|
109
|
+
* called "#url=" with http://cnn.com [sequel-4.21.0/lib/sequel/model/base.rb:858]
|
110
|
+
* called "#typecast_on_assignment" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
111
|
+
* called "#db_schema" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
112
|
+
* called "#db_schema" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
113
|
+
* called "#db_schema" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
114
|
+
* called "#db_schema" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
115
|
+
* called "#raise_on_typecast_failure" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
116
|
+
* called "#model" [RUBY CORE]
|
117
|
+
* called "#db" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
118
|
+
* called "#new?" [sequel-4.21.0/lib/sequel/model/base.rb:1454]
|
119
|
+
* called "#model" [RUBY CORE]
|
120
|
+
* called ".autoreloading_associations" [sequel-4.21.0/lib/sequel/model/associations.rb:1417]
|
121
|
+
* called "#changed_columns" [sequel-4.21.0/lib/sequel/model/base.rb:1252]
|
122
|
+
* called "#changed_columns" [sequel-4.21.0/lib/sequel/model/base.rb:1252]
|
123
|
+
* called "#save" [sequel-4.21.0/lib/sequel/model/base.rb:1539]
|
124
|
+
* called "#frozen?" [RUBY CORE]
|
125
|
+
* called "#new?" [sequel-4.21.0/lib/sequel/model/base.rb:1454]
|
126
|
+
* called "#model" [RUBY CORE]
|
127
|
+
* called ".create_timestamp_field" [sequel-4.21.0/lib/sequel/plugins/timestamps.rb:40]
|
128
|
+
* called "#respond_to?" with created_at [RUBY CORE]
|
129
|
+
* called "#respond_to?" with created_at= [RUBY CORE]
|
130
|
+
* called "#model" [RUBY CORE]
|
131
|
+
* called ".create_timestamp_overwrite?" [sequel-4.21.0/lib/sequel/plugins/timestamps.rb:46]
|
132
|
+
* called "#get_column_value" with created_at [RUBY CORE]
|
133
|
+
* called "#created_at" [sequel-4.21.0/lib/sequel/model/base.rb:857]
|
134
|
+
* called "#model" [RUBY CORE]
|
135
|
+
* called ".dataset" [sequel-4.21.0/lib/sequel/model/base.rb:157]
|
136
|
+
* called "#set_column_value" with created_at=, 2015-07-07 19:16:24 -0700 [RUBY CORE]
|
137
|
+
* called "#created_at=" with 2015-07-07 19:16:24 -0700 [sequel-4.21.0/lib/sequel/model/base.rb:858]
|
138
|
+
* called "#typecast_on_assignment" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
139
|
+
* called "#db_schema" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
140
|
+
* called "#db_schema" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
141
|
+
* called "#db_schema" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
142
|
+
* called "#db_schema" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
143
|
+
* called "#raise_on_typecast_failure" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
144
|
+
* called "#model" [RUBY CORE]
|
145
|
+
* called "#db" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
146
|
+
* called "#new?" [sequel-4.21.0/lib/sequel/model/base.rb:1454]
|
147
|
+
* called "#model" [RUBY CORE]
|
148
|
+
* called ".autoreloading_associations" [sequel-4.21.0/lib/sequel/model/associations.rb:1417]
|
149
|
+
* called "#changed_columns" [sequel-4.21.0/lib/sequel/model/base.rb:1252]
|
150
|
+
* called "#model" [RUBY CORE]
|
151
|
+
* called ".set_update_timestamp_on_create?" [sequel-4.21.0/lib/sequel/plugins/timestamps.rb:54]
|
152
|
+
* called "#model" [RUBY CORE]
|
153
|
+
* called ".update_timestamp_field" [sequel-4.21.0/lib/sequel/plugins/timestamps.rb:43]
|
154
|
+
* called "#respond_to?" with updated_at= [RUBY CORE]
|
155
|
+
* called "#set_column_value" with updated_at=, 2015-07-07 19:16:24 -0700 [RUBY CORE]
|
156
|
+
* called "#updated_at=" with 2015-07-07 19:16:24 -0700 [sequel-4.21.0/lib/sequel/model/base.rb:858]
|
157
|
+
* called "#typecast_on_assignment" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
158
|
+
* called "#db_schema" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
159
|
+
* called "#db_schema" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
160
|
+
* called "#db_schema" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
161
|
+
* called "#db_schema" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
162
|
+
* called "#raise_on_typecast_failure" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
163
|
+
* called "#model" [RUBY CORE]
|
164
|
+
* called "#db" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
165
|
+
* called "#new?" [sequel-4.21.0/lib/sequel/model/base.rb:1454]
|
166
|
+
* called "#model" [RUBY CORE]
|
167
|
+
* called ".autoreloading_associations" [sequel-4.21.0/lib/sequel/model/associations.rb:1417]
|
168
|
+
* called "#changed_columns" [sequel-4.21.0/lib/sequel/model/base.rb:1252]
|
169
|
+
* called "#raise_on_save_failure" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
170
|
+
* called "#frozen?" [RUBY CORE]
|
171
|
+
* called "#raise_on_save_failure" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
172
|
+
* called "#frozen?" [RUBY CORE]
|
173
|
+
* called "#errors" [sequel-4.21.0/lib/sequel/model/base.rb:1301]
|
174
|
+
* called "#around_validation" [sequel-4.21.0/lib/sequel/model/base.rb:1124]
|
175
|
+
* called "#before_validation" [sequel-4.21.0/lib/sequel/model/base.rb:1123]
|
176
|
+
* called "#validate" [apps/website-report-service/app/models/website_report.rb:7]
|
177
|
+
* called "#validates_presence" with user_id, url [sequel-4.21.0/lib/sequel/plugins/validation_helpers.rb:176]
|
178
|
+
* called "#get_column_value" with user_id [RUBY CORE]
|
179
|
+
* called "#user_id" [sequel-4.21.0/lib/sequel/model/base.rb:857]
|
180
|
+
* called "#model" [RUBY CORE]
|
181
|
+
* called "#db" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
182
|
+
* called "#get_column_value" with url [RUBY CORE]
|
183
|
+
* called "#url" [sequel-4.21.0/lib/sequel/model/base.rb:857]
|
184
|
+
* called "#model" [RUBY CORE]
|
185
|
+
* called "#db" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
186
|
+
* called "#after_validation" [sequel-4.21.0/lib/sequel/model/base.rb:1123]
|
187
|
+
* called "#errors" [sequel-4.21.0/lib/sequel/model/base.rb:1301]
|
188
|
+
* called "#errors" [sequel-4.21.0/lib/sequel/model/base.rb:1301]
|
189
|
+
* called "#raise_on_save_failure" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
190
|
+
* called "#use_transactions" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
191
|
+
* called "#frozen?" [RUBY CORE]
|
192
|
+
* called "#use_transactions" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
193
|
+
* called "#db" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
194
|
+
* called "#db" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
195
|
+
* called "#model" [RUBY CORE]
|
196
|
+
* called ".dataset" [sequel-4.21.0/lib/sequel/model/base.rb:157]
|
197
|
+
I, [2015-07-07T19:16:24.477282 #39091] INFO -- : (0.000231s) BEGIN
|
198
|
+
* called "#model" [RUBY CORE]
|
199
|
+
* called ".dataset" [sequel-4.21.0/lib/sequel/model/base.rb:157]
|
200
|
+
* called "#use_after_commit_rollback" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
201
|
+
* called "#frozen?" [RUBY CORE]
|
202
|
+
* called "#use_after_commit_rollback" [sequel-4.21.0/lib/sequel/model/base.rb:1135]
|
203
|
+
* called "#db" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
204
|
+
* called "#db" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
205
|
+
* called "#around_save" [sequel-4.21.0/lib/sequel/model/base.rb:1124]
|
206
|
+
* called "#before_save" [sequel-4.21.0/lib/sequel/model/base.rb:1123]
|
207
|
+
* called "#new?" [sequel-4.21.0/lib/sequel/model/base.rb:1454]
|
208
|
+
* called "#around_create" [sequel-4.21.0/lib/sequel/model/base.rb:1124]
|
209
|
+
* called "#before_create" [sequel-4.21.0/lib/sequel/model/base.rb:1123]
|
210
|
+
* called "#model" [RUBY CORE]
|
211
|
+
* called ".instance_dataset" [sequel-4.21.0/lib/sequel/model/base.rb:30]
|
212
|
+
I, [2015-07-07T19:16:24.479095 #39091] INFO -- : (0.001098s) INSERT INTO "websites" ("user_id", "url", "created_at", "updated_at") VALUES (101, 'http://cnn.com', '2015-07-07 19:16:24.476029-0700', '2015-07-07 19:16:24.476029-0700') RETURNING *
|
213
|
+
* called "#after_create" [sequel-4.21.0/lib/sequel/model/base.rb:1123]
|
214
|
+
* called "#after_save" [sequel-4.21.0/lib/sequel/model/base.rb:1123]
|
215
|
+
* called "#changed_columns" [sequel-4.21.0/lib/sequel/model/base.rb:1252]
|
216
|
+
* called "#db" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
217
|
+
* called "#db" [sequel-4.21.0/lib/sequel/model/base.rb:1130]
|
218
|
+
I, [2015-07-07T19:16:24.481081 #39091] INFO -- : (0.000411s) COMMIT
|
219
|
+
* called "#after_commit" [sequel-4.21.0/lib/sequel/model/base.rb:1123]
|
220
|
+
* called "#inspect" [sequel-4.21.0/lib/sequel/model/base.rb:1368]
|
221
|
+
* called "#model" [RUBY CORE]
|
222
|
+
* called ".name" [RUBY CORE]
|
60
223
|
```
|
61
224
|
|
225
|
+
141 method calls to create a new record with 2 columns!
|
226
|
+
|
227
|
+
|
62
228
|
## Troubleshooting
|
63
229
|
|
64
230
|
Having problems? Maybe a specific method is throwing some obscure error? Try ignoring that method, so we can get back on track!
|
65
231
|
|
66
232
|
```ruby
|
67
|
-
|
68
|
-
|
233
|
+
MyKlass.track_not :bad_method
|
234
|
+
MyKlass.track_all! #=> will exclude tracking for :bad_method
|
69
235
|
```
|
70
236
|
|
71
237
|
## Issues
|
72
238
|
|
73
|
-
|
239
|
+
Doesn't work well (or at all) when trying to track Ruby core objects (`String`, `Array`, etc). You can work around this by
|
74
240
|
subclassing the target class before extending with `ObjectTracker`. For example:
|
75
241
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
## Contributing
|
83
|
-
|
84
|
-
1. Fork it ( https://github.com/[my-github-username]/object_tracker/fork )
|
85
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
86
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
87
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
88
|
-
5. Create a new Pull Request
|
242
|
+
```ruby
|
243
|
+
class MyArray < Array
|
244
|
+
extend ObjectTracker
|
245
|
+
end
|
246
|
+
```
|
data/lib/object_tracker.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
require
|
1
|
+
require 'benchmark'
|
2
|
+
require 'object_tracker/version'
|
2
3
|
|
3
4
|
fail "ObjectTracker #{ObjectTracker::VERSION} only supports Ruby 2+" if RUBY_VERSION < '2.0.0'
|
4
5
|
|
@@ -56,8 +57,11 @@ module ObjectTracker
|
|
56
57
|
msg = %Q( * called "#{method_name}" )
|
57
58
|
msg << "with " << args.join(', ') << " " if args.any?
|
58
59
|
msg << "[#{source_def}]"
|
60
|
+
result = nil
|
61
|
+
time = Benchmark.realtime { result = super }
|
62
|
+
msg << " (" << time.to_s << ")"
|
59
63
|
puts msg
|
60
|
-
|
64
|
+
result
|
61
65
|
rescue NoMethodError => e
|
62
66
|
raise e if e.message !~ /no superclass/
|
63
67
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: object_tracker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.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-08-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -74,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
74
74
|
version: '0'
|
75
75
|
requirements: []
|
76
76
|
rubyforge_project:
|
77
|
-
rubygems_version: 2.
|
77
|
+
rubygems_version: 2.4.8
|
78
78
|
signing_key:
|
79
79
|
specification_version: 4
|
80
80
|
summary: Track method calls to almost any object.
|