dyoder-auto_code 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,104 @@
1
+ module AutoCode
2
+
3
+ # always make sure we have a camel-cased symbol
4
+ def AutoCode.normalize( cname )
5
+ return cname unless cname.is_a? String
6
+ cname.gsub(/(_)(\w)/) { $2.upcase }.gsub(/^([a-z])/) { $1.upcase }.intern
7
+ end
8
+
9
+ class Loader
10
+ def initialize(options={}); @directories = options[:directories] ; end
11
+ def call(cname)
12
+ if @directories.nil?
13
+ Kernel.load( Loader.snake_case( cname.to_s ) << '.rb' )
14
+ else
15
+ filename = Loader.snake_case( cname.to_s ) << '.rb'
16
+ path = @directories.map { |dir| File.join( dir.to_s, filename ) }.find { |path| File.exist?( path ) }
17
+ Kernel.load( path ) rescue nil unless path.nil?
18
+ end
19
+ end
20
+ def Loader.snake_case(cname)
21
+ cname.gsub(/([a-z\d])([A-Z])/){"#{$1}_#{$2}"}.tr("-", "_").downcase
22
+ end
23
+ end
24
+
25
+ class Creator
26
+ def initialize( options, &block )
27
+ @exemplar = (options[:exemplar]||Module.new).clone; @block = block
28
+ end
29
+ def call ; @exemplar.module_eval( &@block ) if @block ; @exemplar ; end
30
+ end
31
+
32
+ class Initializer
33
+ def initialize( &block ) ;@block = block ; end
34
+ def call( mod ) ; mod.module_eval( &@block ) ; end
35
+ end
36
+
37
+ def self.extended( mod ) ; included(mod) ; end
38
+
39
+ def self.included( mod )
40
+
41
+ mod.instance_eval do
42
+
43
+ # Initialize bookkeeping variables needed by AutoCode
44
+ @initializers = Hash.new { |h,k| h[k] = [] }; @reloadable = []
45
+
46
+ # Adds an auto_create block for the given key using the given exemplar if provided
47
+ def auto_create( key = true, options = {}, &block )
48
+ @initializers[ AutoCode.normalize( key ) ] << Creator.new( options, &block ); self
49
+ end
50
+
51
+ # Adds an auto_load block for the given key and directories
52
+ def auto_load( key = true, options = {} )
53
+ @initializers[ AutoCode.normalize( key ) ].unshift( Loader.new( options ) ); self
54
+ end
55
+
56
+ # Adds an arbitrary initializer block for the given key
57
+ def auto_eval( key, &block )
58
+ @initializers[ AutoCode.normalize( key ) ] << Initializer.new( &block ); self
59
+ end
60
+
61
+ # Convenience method for auto_create.
62
+ def auto_create_class( key = true, superclass = Object, &block )
63
+ auto_create( key,{ :exemplar => Class.new( superclass ) }, &block )
64
+ end
65
+
66
+ # Convenience method for auto_create.
67
+ def auto_create_module( key = true, &block )
68
+ auto_create( key,{ :exemplar => Module.new }, &block )
69
+ end
70
+
71
+ # Reloading stuff ...
72
+
73
+ # Returns the list of constants that would be reloaded upon a call to reload.
74
+ def reloadable( *names ) ; @reloadable + names ; end
75
+
76
+ # Reloads all the constants that were loaded via auto_code. Technically, all reload
77
+ # is doing is undefining them (by calling +remove_const+ on each in turn); they won't get
78
+ # reloaded until they are referenced.
79
+ def reload ; @reloadable.each { |name| remove_const( name ) } ; @reloadable = nil ; self; end
80
+
81
+ # Unloads all the constants that were loaded and removes all auto* definitions.
82
+ def unload ; reload ; @initializers = nil ; self ; end
83
+
84
+ private
85
+
86
+ old = method( :const_missing )
87
+ (class << self ; self ; end ).instance_eval do
88
+ define_method :const_missing do | cname |
89
+ ( @initializers[cname] + @initializers[true] ).each do |initializer|
90
+ case initializer
91
+ when Loader then initializer.call( cname ) unless const_defined?(cname)
92
+ when Creator then const_set( cname, initializer.call ) unless const_defined?(cname)
93
+ else
94
+ return old.call(cname) unless const_defined?( cname )
95
+ initializer.call( const_get( cname ) ) if const_defined?( cname )
96
+ end
97
+ end
98
+ return old.call(cname) unless const_defined?( cname )
99
+ @reloadable << cname ; const_get( cname )
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,28 @@
1
+ require File.join(File.dirname(__FILE__), 'helpers.rb')
2
+
3
+ describe "auto_create should" do
4
+
5
+ before do
6
+ A.reload if defined? A and A.respond_to? :reload
7
+ module A
8
+ include AutoCode
9
+ auto_create_module :B do
10
+ include AutoCode
11
+ auto_create_class
12
+ end
13
+ end
14
+ end
15
+
16
+ specify "allow you create and initialize a given const name" do
17
+ A::B.class.should == Module
18
+ end
19
+
20
+ specify "allow you create and initialize const using a wildcard" do
21
+ A::B::C.class.should === Class
22
+ end
23
+
24
+ specify "should raise a NameError if a const doesn't match" do
25
+ lambda{ A::C }.should.raise NameError
26
+ end
27
+
28
+ end
@@ -0,0 +1,21 @@
1
+ require File.join(File.dirname(__FILE__), 'helpers.rb')
2
+
3
+ describe "auto_eval should" do
4
+
5
+ before do
6
+ A.reload if defined? A and A.respond_to? :reload
7
+ module A
8
+ include AutoCode
9
+ auto_create_module :B
10
+ auto_eval :B do
11
+ include AutoCode
12
+ auto_create_class
13
+ end
14
+ end
15
+ end
16
+
17
+ specify "allow you to run blocks after an object is first created" do
18
+ A::B::C.class.should == Class
19
+ end
20
+
21
+ end
@@ -0,0 +1,42 @@
1
+ require File.join(File.dirname(__FILE__), 'helpers.rb')
2
+ require 'extensions/io'
3
+
4
+
5
+ describe "auto_load should" do
6
+
7
+ before do
8
+ A.reload if defined? A and A.respond_to? :reload
9
+ @path = File.join( 'auto_load', 'b.rb' )
10
+ content =<<-EOF
11
+ module A
12
+ module B
13
+ end
14
+ end
15
+ EOF
16
+ File.write( @path, content )
17
+ module A
18
+ include AutoCode
19
+ auto_create_class :B
20
+ auto_load :B, :directories => [ 'auto_load' ]
21
+ auto_create_class :B
22
+ end
23
+
24
+ end
25
+
26
+ after do
27
+ FileUtils.rm( File.join( @path ) )
28
+ end
29
+
30
+ specify "allow you to load a file to define a const" do
31
+ A::B.class.should == Module
32
+ end
33
+
34
+ specify "should raise a NameError if a const doesn't match" do
35
+ lambda{ A::C }.should.raise NameError
36
+ end
37
+
38
+ specify "always take precedence over auto_create" do
39
+ A::B.class.should == Module
40
+ end
41
+
42
+ end
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ %w{ bacon metaid }.each { |dep| require dep }
3
+ # Bacon.extend Bacon::TestUnitOutput
4
+ Bacon.summary_on_exit
5
+
6
+ module Kernel
7
+ private
8
+ def specification(name, &block) Bacon::Context.new(name, &block) end
9
+ end
10
+
11
+ Bacon::Context.instance_eval do
12
+ alias_method :specify, :it
13
+ end
14
+
15
+ require '../lib/auto_code'
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dyoder-auto_code
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.8
5
+ platform: ruby
6
+ authors:
7
+ - Dan Yoder
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-05-11 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/auto_code.rb
34
+ - test/auto_create.rb
35
+ - test/auto_eval.rb
36
+ - test/auto_load
37
+ - test/auto_load.rb
38
+ - test/helpers.rb
39
+ has_rdoc: true
40
+ homepage: http://dev.zeraweb.com/
41
+ post_install_message:
42
+ rdoc_options: []
43
+
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 1.8.6
51
+ version:
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ requirements: []
59
+
60
+ rubyforge_project:
61
+ rubygems_version: 1.0.1
62
+ signing_key:
63
+ specification_version: 2
64
+ summary: Utility for auto-including, reloading, and generating classes and modules.
65
+ test_files: []
66
+