dyoder-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.
data/lib/autocode.rb ADDED
@@ -0,0 +1,112 @@
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
+ @exemplars ||= Hash.new
17
+ @init_blocks ||= Hash.new { |h,k| h[k] = [] }
18
+ keys.each do |k|
19
+ @exemplars[k] = exemplar
20
+ @init_blocks[k] << block
21
+ end
22
+
23
+ return self
24
+ end
25
+
26
+ def autoinit( key, &block )
27
+ # See whether we're dealing with a namespaced constant,
28
+ # The match groupings for, e.g. "X::Y::Z", would be
29
+ # ["X::Y", "Z"]
30
+ match = key.to_s.match(/^(.*)::([\w\d_]+)$/)
31
+ if match
32
+ namespace, cname = match[1,2]
33
+ const = module_eval(namespace)
34
+ const.module_eval do
35
+ @init_blocks ||= Hash.new { |h,k| h[k] = [] }
36
+ @init_blocks[cname.to_sym] << block
37
+ end
38
+ else
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 ||= Hash.new
58
+ @load_files[key] = [file_finder, options[:exemplar]]
59
+ return self
60
+ end
61
+
62
+ def autoload_class(key, superclass=nil, options={})
63
+ options[:exemplar] = Class.new(superclass)
64
+ autoload key, options
65
+ end
66
+
67
+ def autoload_module(key, options={})
68
+ options[:exemplar] = Module.new
69
+ autoload key, options
70
+ end
71
+
72
+
73
+ define_method :const_missing do | cname | #:nodoc:
74
+ cname = cname.to_sym
75
+ @exemplars ||= Hash.new
76
+ @init_blocks ||= Hash.new { |h,k| h[k] = [] }
77
+ @load_files ||= Hash.new
78
+ exemplar = @exemplars[cname] || @exemplars[true]
79
+ blocks = @init_blocks[cname]
80
+ blocks = @init_blocks[true] + blocks if @exemplars[cname].nil? && @init_blocks[true]
81
+ load_file_finder, load_class = @load_files[cname] || @load_files[true]
82
+
83
+ if load_file_finder && filename = load_file_finder.call(cname)
84
+ object = load_class.clone
85
+ elsif exemplar
86
+ object = exemplar.clone
87
+ else
88
+ return old.call(cname)
89
+ end
90
+
91
+ (@reloadable ||= []) << cname;
92
+ const_set( cname, object )
93
+
94
+ blocks.each do |block|
95
+ object.module_eval( &block) if block
96
+ end
97
+ load(filename) if filename
98
+ return object
99
+ end
100
+
101
+ def default_file_name(cname)
102
+ ( cname.to_s.gsub(/([a-z\d])([A-Z\d])/){ "#{$1}_#{$2}"} << ".rb" ).downcase
103
+ end
104
+
105
+ def default_directory(module_name)
106
+ m = self.name.match( /^.*::([\w\d_]+)$/)
107
+ m[1].snake_case
108
+ end
109
+
110
+ end
111
+ end
112
+ end
data/lib/reloadable.rb ADDED
@@ -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
data/test/autoinit.rb ADDED
@@ -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
data/test/autoload.rb ADDED
@@ -0,0 +1,24 @@
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 true, 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
+ it "should autoload where files match" do
16
+ Thingy::Mabob::DooDad.should.respond_to :gizmo
17
+ Thingy::Mabob::Humbug.should.respond_to :full_of_it?
18
+ end
19
+
20
+ it "should not autocreate those unmentioned and fileable" do
21
+ lambda { Thingy::Mabob::MooCow }.should.raise NameError
22
+ end
23
+
24
+ end
data/test/helpers.rb ADDED
@@ -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: dyoder-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
+