nil-passer 0.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 +7 -0
- data/lib/nil_passer.rb +178 -0
- metadata +44 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f6d055dc32bd54aaaaf42bcd4855ed0495a66d90
|
4
|
+
data.tar.gz: a6ebb173920fb8932ea10737597b3a2929c5d5c9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b8ebd1d43e856966534755ad0b52bd31a037db688039c36da80ae9297a856d9a0c24d03b038ae7690ede4b71ea40118bdabbd78aacd752bfeec2185c68448be1
|
7
|
+
data.tar.gz: 25842a53a205c36958d3460d264f6e657904c7766a92cd494918fff89009af9860116cafb1fe981841e2807dfc43e4d642473df16012483781194fa9ef60caa5
|
data/lib/nil_passer.rb
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'rails'
|
2
|
+
|
3
|
+
class NilPasser
|
4
|
+
attr_accessor :obj, :method_name, :orig_proc
|
5
|
+
@@rails_path ||= Rails.root.to_s
|
6
|
+
@@rails_logger ||= Rails.logger
|
7
|
+
|
8
|
+
def self.test(a_caller, block)
|
9
|
+
if (block&.arity == 1) && a_caller.first&.start_with?(@@rails_path)
|
10
|
+
begin
|
11
|
+
block.call nil
|
12
|
+
rescue Exception => e
|
13
|
+
@@rails_logger.tagged("no-nil") { @@rails_logger.info "found a block that can't handle nil at #{block.source_location}, error: #{e.inspect}" }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.clone(klass, method_name)
|
19
|
+
begin
|
20
|
+
# ensure that the method is not recursively redefined
|
21
|
+
klass.class_variable_get("@@old_#{method_name}".to_sym)
|
22
|
+
rescue NameError
|
23
|
+
klass.instance_method(method_name).clone
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.teardown(nil_passers)
|
28
|
+
nil_passers.each do |nil_passer|
|
29
|
+
nil_passer.teardown
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(obj, method_name=nil, accepts_args=true)
|
34
|
+
if obj.is_a? Class
|
35
|
+
self.initialize_class obj, method_name, accepts_args
|
36
|
+
else
|
37
|
+
self.initialize_instance obj, method_name, accepts_args
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# stuff -> @@old_stuff
|
42
|
+
def to_old(x)
|
43
|
+
# need to convert method-only symbols into symbols acceptible for class variables
|
44
|
+
clean_x = x.to_s.gsub(/[^0-9a-zA-Z_]/) do |y|
|
45
|
+
y.codepoints.map do |z|
|
46
|
+
z.to_s
|
47
|
+
end.join('_')
|
48
|
+
end
|
49
|
+
"@@old_#{clean_x}".to_sym
|
50
|
+
end
|
51
|
+
|
52
|
+
def initialize_class(klass, method_name=nil, accepts_args=true)
|
53
|
+
if method_name
|
54
|
+
obj.class.class_variable_set(to_old method_name, NilPasser.clone(obj, method_name))
|
55
|
+
if accepts_args
|
56
|
+
# I don't know how to send this to klass without eval
|
57
|
+
eval [ "class #{klass}",
|
58
|
+
" def #{method_name}(*args, &block)",
|
59
|
+
" NilPasser.test caller, block",
|
60
|
+
" #{to_old method_name}.bind(self)&.call(*args, &block)",
|
61
|
+
" end",
|
62
|
+
"end"
|
63
|
+
].join("\n")
|
64
|
+
else
|
65
|
+
eval [ "class #{klass}",
|
66
|
+
" def #{method_name}(&block)",
|
67
|
+
" NilPasser.test caller, block",
|
68
|
+
" #{to_old method_name}.bind(self)&.call(&block)",
|
69
|
+
" end",
|
70
|
+
"end"
|
71
|
+
].join("\n")
|
72
|
+
end
|
73
|
+
else
|
74
|
+
obj.methods.map do |method|
|
75
|
+
NilPasser.new(obj, method)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def initialize_instance(inst, method_name=nil, accepts_args=true)
|
81
|
+
if method_name
|
82
|
+
begin
|
83
|
+
@obj = inst
|
84
|
+
@method_name = method_name
|
85
|
+
@orig_proc = inst.method(method_name).to_proc
|
86
|
+
rescue NameError => e
|
87
|
+
raise ArgumentError, "The provided method must be a valid method of the provided object, got: #{e}"
|
88
|
+
end
|
89
|
+
else
|
90
|
+
(inst.methods - Object.methods).map do |method|
|
91
|
+
NilPasser.new(obj, method)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def setup
|
97
|
+
@orig_proc = self.obj.method(@method_name).to_proc.clone
|
98
|
+
@obj.send(:define_singleton_method, @method_name, self.method(:call).to_proc)
|
99
|
+
self
|
100
|
+
end
|
101
|
+
|
102
|
+
def call(*args, &block)
|
103
|
+
NilPasser.test caller, block
|
104
|
+
@orig_proc.call(*args, &block)
|
105
|
+
end
|
106
|
+
|
107
|
+
def teardown
|
108
|
+
@obj.send(:define_singleton_method, @method_name, @orig_proc)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# def generate_nil_passers(klass, methods, no_arg_methods=[])
|
113
|
+
# methods = methods.select do |method|
|
114
|
+
# begin
|
115
|
+
# klass.instance_method method
|
116
|
+
# true
|
117
|
+
# rescue NameError
|
118
|
+
# false
|
119
|
+
# end
|
120
|
+
# end
|
121
|
+
|
122
|
+
# no_arg_methods = no_arg_methods.select do |method|
|
123
|
+
# begin
|
124
|
+
# klass.instance_method method
|
125
|
+
# true
|
126
|
+
# rescue NameError
|
127
|
+
# false
|
128
|
+
# end
|
129
|
+
# end
|
130
|
+
|
131
|
+
# old_decls = (methods + no_arg_methods).map do |method|
|
132
|
+
# "@@old_#{sane method} = NilPasser.clone #{klass}, :#{method}"
|
133
|
+
# end.map{|str| " " + str}
|
134
|
+
|
135
|
+
# new_decls = methods.map do |method|
|
136
|
+
# [ "def #{method}(*args, &block)",
|
137
|
+
# " NilPasser.test caller, block",
|
138
|
+
# " @@old_#{sane method}.bind(self)&.call(*args, &block)",
|
139
|
+
# "end"
|
140
|
+
# ].map{|str| " " + str}
|
141
|
+
# end
|
142
|
+
|
143
|
+
# new_no_arg_decls = no_arg_methods.map do |method|
|
144
|
+
# [ "def #{method}(&block)",
|
145
|
+
# " NilPasser.test caller, block",
|
146
|
+
# " @@old_#{sane method}.bind(self)&.call(&block)",
|
147
|
+
# "end"
|
148
|
+
# ].map{|str| " " + str}
|
149
|
+
# end
|
150
|
+
|
151
|
+
# [ "class #{klass}",
|
152
|
+
# old_decls,
|
153
|
+
# new_decls,
|
154
|
+
# new_no_arg_decls,
|
155
|
+
# "end"
|
156
|
+
# ].flatten.join("\n")
|
157
|
+
# end
|
158
|
+
|
159
|
+
# def generate_all_nil_passers(klass)
|
160
|
+
# generate_nil_passers klass, (klass.methods - klass.superclass.methods).select{|x| x.to_s.present?}
|
161
|
+
# end
|
162
|
+
|
163
|
+
# eval generate_all_nil_passers(ActiveRecord::Relation)
|
164
|
+
# eval generate_all_nil_passers(Hash)
|
165
|
+
# eval generate_all_nil_passers(Enumerator)
|
166
|
+
# eval generate_all_nil_passers(Array)
|
167
|
+
# eval generate_all_nil_passers(String)
|
168
|
+
|
169
|
+
|
170
|
+
# eval generate_nil_passers(ActiveRecord::Relation, [:select, :find_each], [:each])
|
171
|
+
# eval generate_nil_passers(Hash, [], [:each_key, :each_value])
|
172
|
+
# eval generate_nil_passers(Enumerator, [], [:each])
|
173
|
+
# eval generate_nil_passers(Array, [:collect, :select], [:each, :map])
|
174
|
+
# eval generate_nil_passers(String, [:each_line])
|
175
|
+
|
176
|
+
# puts "**** loaded nil passer *********"
|
177
|
+
|
178
|
+
|
metadata
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nil-passer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Klein
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-03-07 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A nil-tester for blocks
|
14
|
+
email: lambdamichael@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/nil_passer.rb
|
20
|
+
homepage: http://github.com/michaeljklein/nil-passer
|
21
|
+
licenses:
|
22
|
+
- MIT
|
23
|
+
metadata: {}
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- lib
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
requirements: []
|
39
|
+
rubyforge_project:
|
40
|
+
rubygems_version: 2.6.8
|
41
|
+
signing_key:
|
42
|
+
specification_version: 4
|
43
|
+
summary: Pass nil to all the blocks in an app, catching and logging exceptions
|
44
|
+
test_files: []
|