automatthew-autocode 0.9.3

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.
@@ -0,0 +1,120 @@
1
+ require 'reloadable'
2
+
3
+ module Autocode
4
+
5
+ def self.extended( mod ) #:nodoc:
6
+
7
+ old = mod.method( :const_missing )
8
+ mod.metaclass.class_eval do
9
+
10
+ def autocreate( key, exemplar, &block )
11
+ keys = case key
12
+ when true, Symbol then [key]
13
+ when Array then key
14
+ end
15
+
16
+ keys.each do |k|
17
+ exemplars[k] = exemplar
18
+ init_blocks[k] << block
19
+ end
20
+
21
+ return self
22
+ end
23
+
24
+ def autoinit( key, &block )
25
+ # See whether we're dealing with a namespaced constant,
26
+ # The match groupings for, e.g. "X::Y::Z", would be
27
+ # ["X::Y", "Z"]
28
+ match = key.to_s.match(/^(.*)::([\w\d_]+)$/)
29
+
30
+ if match
31
+ namespace, cname = match[1,2]
32
+ const = module_eval(namespace)
33
+ const.module_eval do
34
+ @init_blocks ||= Hash.new { |h,k| h[k] = [] }
35
+ @init_blocks[cname.to_sym] << block
36
+ end
37
+ else
38
+ @init_blocks ||= Hash.new { |h,k| h[k] = [] }
39
+ @init_blocks[key] << block
40
+ end
41
+ return self
42
+ end
43
+
44
+ def autoload( key, options )
45
+ # look for load_files in either a specified directory, or in the directory
46
+ # with the snakecase name of the enclosing module
47
+ directories = [options[:directories] || default_directory(self.name)].flatten
48
+ # create a lambda that looks for a file to load
49
+ file_finder = lambda do |cname|
50
+ filename = default_file_name(cname)
51
+ dirname = directories.find do |dir|
52
+ File.exist?(File.join(dir.to_s, filename))
53
+ end
54
+ dirname ? File.join(dirname.to_s, filename) : nil
55
+ end
56
+ # if no exemplar is given, assume Module.new
57
+ load_files[key] = [file_finder, options[:exemplar] || Module.new]
58
+ return self
59
+ end
60
+
61
+ def autoload_class(key, superclass=nil, options={})
62
+ options[:exemplar] = Class.new(superclass)
63
+ autoload key, options
64
+ end
65
+
66
+
67
+ define_method :const_missing do | cname | #:nodoc:
68
+ cname = cname.to_sym
69
+ exemplar = exemplars[cname] || exemplars[true]
70
+ blocks = init_blocks[cname]
71
+ blocks = init_blocks[true] + blocks if exemplars[cname].nil? && init_blocks[true]
72
+ load_file_finder, load_class = load_files[cname] || load_files[true]
73
+
74
+ if load_file_finder && filename = load_file_finder.call(cname)
75
+ object = load_class.clone
76
+ elsif exemplar
77
+ object = exemplar.clone
78
+ else
79
+ return old.call(cname)
80
+ end
81
+
82
+ (@reloadable ||= []) << cname;
83
+ const_set( cname, object )
84
+
85
+ blocks.each do |block|
86
+ object.module_eval( &block) if block
87
+ end
88
+ load(filename) if filename
89
+ return object
90
+ end
91
+
92
+ # helper methods. May need to make them private.
93
+ def exemplars
94
+ @exemplars ||= Hash.new
95
+ end
96
+
97
+ def init_blocks
98
+ @init_blocks ||= Hash.new { |h,k| h[k] = [] }
99
+ end
100
+
101
+ def load_files
102
+ @load_files ||= Hash.new
103
+ end
104
+
105
+ def reloadable
106
+ @reloadable ||= []
107
+ end
108
+
109
+ def default_file_name(cname)
110
+ ( cname.to_s.gsub(/([a-z\d])([A-Z\d])/){ "#{$1}_#{$2}"} << ".rb" ).downcase
111
+ end
112
+
113
+ def default_directory(module_name)
114
+ m = self.name.match( /^.*::([\w\d_]+)$/)
115
+ m[1].snake_case
116
+ end
117
+
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ require 'metaid'
3
+
4
+ # Reloadable simply makes it possible for a module's code to be reloaded. *Important*: Only code loaded via Autoload or Autocreate will be reloaded. Also, the module itself is not reloaded, only the modules and classes within it that were loaded via *Autocode*.
5
+ #
6
+ # To use Reloadable, simply extend a given module with Reloadable. This will add two methods to the module: reloadable and reload. These are described below.
7
+
8
+ module Reloadable
9
+
10
+ def self.extended( mod ) #:nodoc:
11
+
12
+ mod.metaclass.class_eval do
13
+
14
+ # Returns the list of constants that would be reloaded upon a call to reload.
15
+ def reloadable( *names )
16
+ ( @reloadable ||= [] ).concat(names)
17
+ return self
18
+ end
19
+
20
+ # Reloads all the constants that were loaded via *Autocode*. Technically, all reload is doing is undefining them (by calling +remove_const+ on each in turn); they won't get reloaded until they are referenced.
21
+ def reload
22
+ ( @reloadable ||=[] ).each { |name| remove_const( name ) }
23
+ @reloadable = []; return self
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -0,0 +1,38 @@
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
+ it "should autocreate some constants" do
18
+ Thingy::Tom.peeps.should == true
19
+ Thingy::Dick.peeps.should == false
20
+ Thingy::Harry.peeps.should == false
21
+ end
22
+
23
+ it "should not autocreate unregistered constants" do
24
+ lambda { Thingy::Mabob::MooCow }.should.raise NameError
25
+ end
26
+
27
+ it "unless autocreate was called with key of true" do
28
+ module Duffel
29
+ extend Autocode
30
+ autocreate true, Class.new do
31
+ def self.universal; true; end
32
+ end
33
+ end
34
+
35
+ Duffel::AnyThing.universal.should == true
36
+ end
37
+
38
+ end
@@ -0,0 +1,52 @@
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 overrides 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
+ it "fdfdsf" do
41
+ Thingy::Whatsit.in_scope.should.be.true
42
+ Thingy::Whatsit::Critter.outside_scope.should.be.true
43
+ Thingy::Whatsit::Critter.new.instance.should.be.true
44
+ Thingy::Big::Bad::John.stinks?.should.be.false
45
+ end
46
+
47
+ it "should run autoinit blocks before the file loading" do
48
+ Thingy::Whatsit::Critter.gizmo.should == 1
49
+ end
50
+
51
+
52
+ end
@@ -0,0 +1,22 @@
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 true, :exemplar => Class.new, :directories => [File.join(File.dirname(__FILE__), "test_lib")]
10
+ end
11
+ end
12
+ end
13
+
14
+ it "should autoload where files match" do
15
+ Thingy::Mabob::DooDad.should.respond_to :gizmo
16
+ end
17
+
18
+ it "should not autocreate those unmentioned and fileable" do
19
+ lambda { Thingy::Mabob::MooCow }.should.raise NameError
20
+ end
21
+
22
+ end
@@ -0,0 +1,8 @@
1
+ %w{ rubygems bacon}.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
+
8
+ # Dir.chdir(File.dirname(__FILE__))
@@ -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,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: automatthew-autocode
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.3
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
+ - lib/reloadable.rb
35
+ - test/autocreate.rb
36
+ - test/autoinit.rb
37
+ - test/autoload.rb
38
+ - test/helpers.rb
39
+ - test/test_lib
40
+ - test/test_lib/critter.rb
41
+ - test/test_lib/doo_dad.rb
42
+ has_rdoc: true
43
+ homepage: http://dev.zeraweb.com/
44
+ post_install_message:
45
+ rdoc_options: []
46
+
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 1.8.6
54
+ version:
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.0.1
65
+ signing_key:
66
+ specification_version: 2
67
+ summary: Utility for auto-including, reloading, and generating classes and modules.
68
+ test_files: []
69
+