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 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
@@ -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
@@ -0,0 +1,7 @@
1
+ %w{ rubygems bacon metaid }.each { |dep| require dep }
2
+ Bacon.extend Bacon::TestUnitOutput
3
+ Bacon.summary_on_exit
4
+
5
+ $:.unshift File.join(File.dirname(__FILE__) , "../lib")
6
+ require 'autocode'
7
+
@@ -0,0 +1,9 @@
1
+ module Thingy
2
+ module Whatsit
3
+ class Critter
4
+ def self.gizmo
5
+ 1
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Thingy
2
+ module Mabob
3
+ class DooDad
4
+ def self.gizmo
5
+ 1
6
+ end
7
+ end
8
+ end
9
+ end
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
+