lawrencepit-autocode 0.9.5
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.
- data/lib/autocode.rb +135 -0
- data/test/autocreate.rb +43 -0
- data/test/autoinit.rb +58 -0
- data/test/autoload.rb +86 -0
- data/test/helpers.rb +7 -0
- data/test/test_lib/critter.rb +9 -0
- data/test/test_lib/doo_dad.rb +9 -0
- metadata +68 -0
data/lib/autocode.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
module Autocode
|
2
|
+
|
3
|
+
def self.extended( mod )
|
4
|
+
included(mod)
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.included( mod )
|
8
|
+
|
9
|
+
old = mod.method( :const_missing )
|
10
|
+
mod.metaclass.class_eval do
|
11
|
+
|
12
|
+
def autocreate( key, exemplar, &block )
|
13
|
+
keys = case key
|
14
|
+
when true, Symbol then [key]
|
15
|
+
when Array then key
|
16
|
+
end
|
17
|
+
|
18
|
+
@exemplars ||= Hash.new
|
19
|
+
@init_blocks ||= Hash.new { |h,k| h[k] = [] }
|
20
|
+
keys.each do |k|
|
21
|
+
@exemplars[k] = exemplar
|
22
|
+
@init_blocks[k] << block
|
23
|
+
end
|
24
|
+
|
25
|
+
return self
|
26
|
+
end
|
27
|
+
|
28
|
+
def autocreate_class( key = true, superclass = Class )
|
29
|
+
autocreate key, Class.new( superclass )
|
30
|
+
end
|
31
|
+
|
32
|
+
def autocreate_module( key = true )
|
33
|
+
autocreate key, Module.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def autoinit( key, &block )
|
37
|
+
# See whether we're dealing with a namespaced constant,
|
38
|
+
# The match groupings for, e.g. "X::Y::Z", would be
|
39
|
+
# ["X::Y", "Z"]
|
40
|
+
match = key.to_s.match(/^(.*)::([\w\d_]+)$/)
|
41
|
+
if match
|
42
|
+
namespace, cname = match[1,2]
|
43
|
+
const = module_eval(namespace)
|
44
|
+
const.module_eval do
|
45
|
+
@init_blocks ||= Hash.new { |h,k| h[k] = [] }
|
46
|
+
@init_blocks[cname.to_sym] << block
|
47
|
+
end
|
48
|
+
else
|
49
|
+
@init_blocks[key] << block
|
50
|
+
end
|
51
|
+
return self
|
52
|
+
end
|
53
|
+
|
54
|
+
def autoload(key = true, options = {})
|
55
|
+
snake_case = lambda {|name| name.gsub(/([a-z\d])([A-Z])/){"#{$1}_#{$2}"}.tr("-", "_").downcase }
|
56
|
+
# look for load_files in either a specified directory, or in the directory
|
57
|
+
# with the snakecase name of the enclosing module
|
58
|
+
directories = [options[:directories] || snake_case.call(self.name.match( /^.*::([\w\d_]+)$/)[1])].flatten
|
59
|
+
# create a lambda that looks for a file to load
|
60
|
+
file_finder = lambda do |cname|
|
61
|
+
filename = snake_case.call(cname.to_s << ".rb")
|
62
|
+
path = directories.map { |dir| File.join(dir.to_s, filename) }.find { |path| File.exist?( path ) }
|
63
|
+
end
|
64
|
+
# if no exemplar is given, assume Module.new
|
65
|
+
@load_files ||= Hash.new
|
66
|
+
@load_files[key] = [file_finder, options[:exemplar] || Module.new]
|
67
|
+
return self
|
68
|
+
end
|
69
|
+
|
70
|
+
def autoload_class(key = true, superclass = Class, options = {})
|
71
|
+
options[:exemplar] = Class.new(superclass)
|
72
|
+
autoload key, options
|
73
|
+
end
|
74
|
+
|
75
|
+
def autoload_module(key = true, options = {})
|
76
|
+
options[:exemplar] = Module.new
|
77
|
+
autoload key, options
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns the list of constants that would be reloaded upon a call to reload.
|
81
|
+
def reloadable( *names )
|
82
|
+
( @reloadable ||= [] ).concat(names)
|
83
|
+
return self
|
84
|
+
end
|
85
|
+
|
86
|
+
# Reloads all the constants that were loaded via autocode. Technically, all reload
|
87
|
+
# is doing is undefining them (by calling +remove_const+ on each in turn); they won't get
|
88
|
+
# reloaded until they are referenced.
|
89
|
+
def reload
|
90
|
+
@reloadable.each { |name| remove_const( name ) } if @reloadable
|
91
|
+
@reloadable = nil
|
92
|
+
return self
|
93
|
+
end
|
94
|
+
|
95
|
+
# Unloads all the constants that were loaded and removes all auto* definitions.
|
96
|
+
def unload
|
97
|
+
reload
|
98
|
+
@exemplars = @init_blocks = @load_files = nil
|
99
|
+
return self
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
define_method :const_missing do | cname | #:nodoc:
|
105
|
+
cname = cname.to_sym
|
106
|
+
@exemplars ||= Hash.new
|
107
|
+
@init_blocks ||= Hash.new { |h,k| h[k] = [] }
|
108
|
+
@load_files ||= Hash.new
|
109
|
+
exemplar = @exemplars[cname] || @exemplars[true]
|
110
|
+
blocks = @init_blocks[cname]
|
111
|
+
blocks = @init_blocks[true] + blocks if @exemplars[cname].nil? && @init_blocks[true]
|
112
|
+
load_file_finder, load_class = @load_files[cname] || @load_files[true]
|
113
|
+
|
114
|
+
if load_file_finder && filename = load_file_finder.call(cname)
|
115
|
+
object = load_class.clone
|
116
|
+
elsif exemplar
|
117
|
+
object = exemplar.clone
|
118
|
+
else
|
119
|
+
return old.call(cname)
|
120
|
+
end
|
121
|
+
|
122
|
+
(@reloadable ||= []) << cname;
|
123
|
+
const_set( cname, object )
|
124
|
+
|
125
|
+
blocks.each do |block|
|
126
|
+
object.module_eval( &block) if block
|
127
|
+
end
|
128
|
+
|
129
|
+
load(filename) if filename
|
130
|
+
|
131
|
+
return object
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
data/test/autocreate.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helpers.rb')
|
2
|
+
|
3
|
+
describe "A module where autocreate has been called" do
|
4
|
+
before do
|
5
|
+
module Thingy
|
6
|
+
extend Autocode
|
7
|
+
autocreate :Tom, Module.new do
|
8
|
+
def self.peeps; true; end
|
9
|
+
end
|
10
|
+
|
11
|
+
autocreate [:Dick, :Harry], Class.new do
|
12
|
+
def self.peeps; false; end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
after do
|
18
|
+
Thingy.unload
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should autocreate some constants" do
|
22
|
+
Thingy::Tom.peeps.should == true
|
23
|
+
Thingy::Dick.peeps.should == false
|
24
|
+
Thingy::Harry.peeps.should == false
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should not autocreate unregistered constants" do
|
28
|
+
lambda { Thingy::Mabob::MooCow }.should.raise NameError
|
29
|
+
end
|
30
|
+
|
31
|
+
it "unless autocreate was called with key of true" do
|
32
|
+
module Duffel
|
33
|
+
extend Autocode
|
34
|
+
autocreate true, Class.new do
|
35
|
+
def self.universal; true; end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Duffel::AnyThing.universal.should == true
|
40
|
+
Duffel.unload
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
data/test/autoinit.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helpers.rb')
|
2
|
+
|
3
|
+
describe "thingy" do
|
4
|
+
before do
|
5
|
+
module Thingy
|
6
|
+
extend Autocode
|
7
|
+
autocreate(:Whatsit, Module.new) do
|
8
|
+
extend Autocode
|
9
|
+
autoload :Critter, :exemplar => Class.new, :directories => File.join(File.dirname(__FILE__), "test_lib")
|
10
|
+
end
|
11
|
+
|
12
|
+
autoinit(:Whatsit) do
|
13
|
+
def self.in_scope; true; end
|
14
|
+
end
|
15
|
+
|
16
|
+
autoinit('Whatsit::Critter') do
|
17
|
+
def self.outside_scope; true; end
|
18
|
+
def instance; true; end
|
19
|
+
# this definition is overridden by the one in the file
|
20
|
+
def self.gizmo; 2; end
|
21
|
+
end
|
22
|
+
|
23
|
+
autocreate :Big, Module.new do
|
24
|
+
extend Autocode
|
25
|
+
autocreate :Bad, Module.new do
|
26
|
+
extend Autocode
|
27
|
+
autocreate :John, Class.new do
|
28
|
+
def self.stinks?; true; end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
autoinit('Big::Bad::John') do
|
34
|
+
def self.stinks?; false; end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
after do
|
41
|
+
Thingy::Whatsit.unload
|
42
|
+
Thingy::Big::Bad.unload
|
43
|
+
Thingy::Big.unload
|
44
|
+
Thingy.unload
|
45
|
+
end
|
46
|
+
|
47
|
+
it "fdfdsf" do
|
48
|
+
Thingy::Whatsit.in_scope.should.be.true
|
49
|
+
Thingy::Whatsit::Critter.outside_scope.should.be.true
|
50
|
+
Thingy::Whatsit::Critter.new.instance.should.be.true
|
51
|
+
Thingy::Big::Bad::John.stinks?.should.be.false
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should run autoinit blocks before the file loading" do
|
55
|
+
Thingy::Whatsit::Critter.gizmo.should == 1
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/test/autoload.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helpers.rb')
|
2
|
+
|
3
|
+
describe "A module where autoload has been called" do
|
4
|
+
|
5
|
+
before do
|
6
|
+
module Thingy
|
7
|
+
module Mabob
|
8
|
+
extend Autocode
|
9
|
+
autoload_class :DooDad, Class, :directories => [File.join(File.dirname(__FILE__), "test_lib")]
|
10
|
+
autoload_module :Humbug, :directories => [File.join(File.dirname(__FILE__), "test_lib")]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
after do
|
16
|
+
Thingy::Mabob.unload
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should autoload where files match" do
|
20
|
+
Thingy::Mabob::DooDad.should.respond_to :gizmo
|
21
|
+
Thingy::Mabob::Humbug.should.respond_to :full_of_it?
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should not autoload where it matches a file but is out of scope" do
|
25
|
+
lambda { Thingy::Mabob::Answer42ItIs }.should.raise NameError
|
26
|
+
lambda { Thingy::Whatsit::Critter }.should.raise NameError
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should not autocreate those unmentioned and fileable" do
|
30
|
+
lambda { Thingy::Mabob::MooCow }.should.raise NameError
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should autoload using super class" do
|
34
|
+
module Waves
|
35
|
+
module TestLib
|
36
|
+
extend Autocode
|
37
|
+
autoload_class true, Thingy::Mabob::DooDad
|
38
|
+
end
|
39
|
+
end
|
40
|
+
Waves::TestLib::TheClass42Gang.party?.should == true
|
41
|
+
Waves::TestLib::TheClass42Gang.gizmo.should == 1
|
42
|
+
Waves::TestLib.unload
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should autoload using defaults" do
|
46
|
+
module Waves
|
47
|
+
module TestLib
|
48
|
+
extend Autocode
|
49
|
+
autoload
|
50
|
+
end
|
51
|
+
end
|
52
|
+
Waves::TestLib::TheOneAndOnlyModule.help().should == "module help"
|
53
|
+
lambda { Waves::TestLib::TheOneAndOnlyClass }.should.raise TypeError
|
54
|
+
Waves::TestLib::ThePretender.name.should == "Waves::TestLib::ThePretender"
|
55
|
+
lambda { Waves::TestLib::ThePretender.help() }.should.raise NoMethodError
|
56
|
+
Waves::TestLib.unload
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should autoload class using defaults" do
|
60
|
+
module Waves
|
61
|
+
module TestLib
|
62
|
+
extend Autocode
|
63
|
+
autoload_class
|
64
|
+
end
|
65
|
+
end
|
66
|
+
Waves::TestLib::TheOneAndOnlyClass.help().should == "class help"
|
67
|
+
lambda { Waves::TestLib::TheOneAndOnlyModule }.should.raise TypeError
|
68
|
+
Waves::TestLib::ThePretender.name.should == "Waves::TestLib::ThePretender"
|
69
|
+
lambda { Waves::TestLib::ThePretender.help() }.should.raise NoMethodError
|
70
|
+
Waves::TestLib.unload
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should autoload module using defaults" do
|
74
|
+
module Waves
|
75
|
+
module TestLib
|
76
|
+
extend Autocode
|
77
|
+
autoload_module
|
78
|
+
end
|
79
|
+
end
|
80
|
+
Waves::TestLib::TheOneAndOnlyModule.help().should == "module help"
|
81
|
+
lambda { Waves::TestLib::TheOneAndOnlyClass }.should.raise TypeError
|
82
|
+
Waves::TestLib::ThePretender.name.should == "Waves::TestLib::ThePretender"
|
83
|
+
lambda { Waves::TestLib::ThePretender.help() }.should.raise NoMethodError
|
84
|
+
Waves::TestLib.unload
|
85
|
+
end
|
86
|
+
end
|
data/test/helpers.rb
ADDED
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lawrencepit-autocode
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dan Yoder
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-04-30 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: metaid
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: "0"
|
23
|
+
version:
|
24
|
+
description:
|
25
|
+
email:
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files: []
|
31
|
+
|
32
|
+
files:
|
33
|
+
- lib/autocode.rb
|
34
|
+
- test/autocreate.rb
|
35
|
+
- test/autoinit.rb
|
36
|
+
- test/autoload.rb
|
37
|
+
- test/helpers.rb
|
38
|
+
- test/test_lib
|
39
|
+
- test/test_lib/critter.rb
|
40
|
+
- test/test_lib/doo_dad.rb
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: http://dev.zeraweb.com/
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 1.8.6
|
53
|
+
version:
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
rubyforge_project:
|
63
|
+
rubygems_version: 1.0.1
|
64
|
+
signing_key:
|
65
|
+
specification_version: 2
|
66
|
+
summary: Utility for auto-including, reloading, and generating classes and modules.
|
67
|
+
test_files: []
|
68
|
+
|