nil-passer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/nil_passer.rb +178 -0
  3. 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: []