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.
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: []