Skip to content

Instantly share code, notes, and snippets.

@kwstannard
Last active October 6, 2015 03:00
Show Gist options
  • Save kwstannard/2bb68f10413c83de5ad4 to your computer and use it in GitHub Desktop.
Save kwstannard/2bb68f10413c83de5ad4 to your computer and use it in GitHub Desktop.
=begin
This class allows you to condsolidate the declaration of class names into
the file name. It also handles namespacing based on the file path if you are
using Rails autoloading.
This works with the single exception of constant lookup via nesting, so you
will need to replace constants with variables and methods.
Examples:
# app/models/user.rb
Dryer.def_class(__FILE__) do
def hi
"hello world"
end
end
User.new.hi
=> "hello world"
# app/models/instruments/horn.rb
Dryer.def_class(__FILE__) do
def play
"toot!"
end
end
Instruments::Horn.new.play
=> "toot!"
# app/models/address.rb
Dryer.def_class(__FILE__, ActiveRecord::Base) do
end
Address.new.respond_to? :save
=> true
=end
class Dryer < Struct.new(:file_path, :super_class, :blk)
def self.def_class(file_path, super_class=Object, &blk)
new(file_path, super_class, blk).def_class
end
def def_class
constant_names.each.with_index.inject(Object) do |const, (next_const, index)|
if constant_names.length == index + 1
# this is needed to set the class name so that activerecord
# works properly
klass = const.const_set(next_const, Class.new(super_class))
# here we eval the class block to define methods and everything
klass.class_eval &blk
else
const.const_get(next_const)
end
end
end
def constant_names
get_name.split('/').map(&:camelcase)
end
def get_name
file_path.gsub(most_likely_path, '').gsub(".rb", '')
end
def most_likely_path
all_autoload_paths.map{|p| file_path[/^#{p}/] || ""}.sort.last + '/'
end
def all_autoload_paths
config = Rails.configuration
config.autoload_paths + config.eager_load_paths + config.autoload_once_paths
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment