Skip to content

Instantly share code, notes, and snippets.

@markburns
Last active February 7, 2017 19:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markburns/2c6d7ec0382fc46a2dfac492d855b8d4 to your computer and use it in GitHub Desktop.
Save markburns/2c6d7ec0382fc46a2dfac492d855b8d4 to your computer and use it in GitHub Desktop.
Print out /fails tests if class instance variables defined in your application code
# Example sets some state
class SomeObject
def self.asdf
@a = 1
end
end
SomeObject.asdf
require "pathname"
module EnemyOfTheState
class << self
attr_accessor :application_directories
end
module ApplicationFolders
extend self
def exclude?(method)
file, _ = method.source_location
return true unless file
!included_in?(expand_path(file), EnemyOfTheState.application_directories)
end
private
def expand_path(f)
Pathname.new(f).expand_path
end
SEPARATOR = "/"
def included_in?(p1, paths)
paths.any? do |p2|
common = common_parent(p1, p2)
common.to_s.length >= p2.to_s.length
end
end
def common_parent(path_a, path_b)
dirs = [
Pathname.new(path_a.to_s).expand_path,
Pathname.new(path_b.to_s).expand_path,
]
dir1, dir2 = dirs.sort.map { |dir| dir.to_s.split(SEPARATOR) }
append_trailing_slash!(path_from(dir1, dir2, path_a, path_b).to_s)
end
def path_from(dir1, dir2, path_a, path_b)
common_path = common_path(dir1, dir2)
common_path, path_a, path_b = append_trailing_slashes!(common_path, path_a, path_b)
Pathname.new(common_path) if valid_length?(common_path, path_a, path_b)
end
def valid_length?(common_path, path_a, path_b)
l = common_path.to_s.length
(l <= path_a.to_s.length) || (l <= path_b.to_s.length)
end
def common_path(dir1, dir2)
dir1.
zip(dir2).
take_while { |dn1, dn2| dn1 == dn2 }.
map(&:first).
join(SEPARATOR)
end
def append_trailing_slash!(path)
path = path.to_s
if Pathname.new(path).directory?
path += SEPARATOR if path && path.to_s[-1] != SEPARATOR
end
path
end
def append_trailing_slashes!(*paths)
paths.map do |path|
append_trailing_slash!(path)
end
end
end
end
require "set"
require_relative "application_folders"
module EnemyOfTheState
class << self
def display
each_class_instance_variable { |s| puts(s) }
end
def fail
each_class_instance_variable { |s| Kernel.fail(s) }
end
private
def each_class_instance_variable(&block)
set = Set.new
application_klasses do |k|
next if k == set || set.include?(k)
set.add(k)
variables_in(k, &block)
end
end
def application_klasses
ObjectSpace.each_object.lazy do |o|
klass = o.is_a?(Module) ? o : o.class rescue next
yield klass
end
end
def variables_in(klass, &block)
return if ignore?(klass)
klass.instance_variables.each do |iv|
val = klass.instance_eval(iv.to_s)
unless val.nil?
yield "non-nil class variable found:\n #{klass} #{iv}: #{val.inspect}"
end
end
end
def ignore?(klass)
methods =
klass.methods.map{|m| klass.method(m)} +
klass.instance_methods.map{|m| klass.instance_method(m) }
methods.all? do |m|
EnemyOfTheState::ApplicationFolders.exclude?(m)
end
end
end
end
require_relative "app/example_code"
require_relative "enemy_of_the_state"
EnemyOfTheState.application_directories = [File.expand_path("./app")]
EnemyOfTheState.display
# OR
# EnemyOfTheState.fail
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment