fun_with_patterns 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/CHANGELOG.markdown +7 -0
- data/Gemfile +1 -1
- data/README.rdoc +54 -0
- data/VERSION +1 -1
- data/lib/fun_with/patterns/get_and_set.rb +16 -2
- data/lib/fun_with/patterns/get_and_set_api.rb +13 -4
- data/lib/fun_with/patterns/loader/class_methods.rb +182 -0
- data/lib/fun_with/patterns/loader/features/bracketwise_lookup.rb +17 -0
- data/lib/fun_with/patterns/loader/loading_styles/eval.rb +23 -0
- data/lib/fun_with/patterns/loader/loading_styles/instance_exec.rb +24 -0
- data/lib/fun_with/patterns/loader/loading_styles/yaml.rb +27 -0
- data/lib/fun_with/patterns/loader.rb +2 -155
- data/lib/fun_with_patterns.rb +2 -4
- data/test/helper.rb +2 -1
- data/test/test_get_and_set.rb +31 -2
- data/test/test_loader_pattern.rb +14 -6
- data/test/user.rb +25 -1
- data/test/users/{mary.rb → eval/mary.rb} +0 -0
- data/test/users/{more → eval/more}/gary.rb +0 -0
- data/test/users/{steve.rb → eval/steve.rb} +0 -0
- data/test/users/{wanda.rb → eval/wanda.rb} +0 -0
- data/test/users/instance_exec/mary.rb +2 -0
- data/test/users/instance_exec/more/gary.rb +2 -0
- data/test/users/instance_exec/steve.rb +2 -0
- data/test/users/instance_exec/wanda.rb +2 -0
- data/test/users/yaml/mary.yaml +3 -0
- data/test/users/yaml/more/gary.yml +3 -0
- data/test/users/yaml/steve.yaml +3 -0
- data/test/users/yaml/wanda.yml +3 -0
- data/test/yaml_obj.rb +2 -1
- metadata +25 -11
- data/lib/fun_with/patterns/hooks.rb +0 -47
- data/lib/fun_with/patterns/reloadable.rb +0 -33
- data/test/reloadable/my_reloadable.rb +0 -7
- data/test/test_hooks.rb +0 -25
- data/test/test_reloadable_pattern.rb +0 -33
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MTQwYjliNzVlNWFkNmYxMjkxZTU4NTY1NmZjZDEwMmNmMTE5NDU0MQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NDAyMWQ1ZTU4M2JiYjdjODkwMGIwM2IwMjM0YjZlMDYxZGY2M2M5Ng==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YmFkOTUzMWQ2MTViZDEzZjZjYTY2NzBmZDU5OTE2NjQ0NzgxODQ1ZGRjYjYx
|
10
|
+
MWFhMTgxOGMyMWE0MjVkYWRiNDcxOGYxODg4Y2VmMDQ2Y2JiYWY4MGQ1Mjc2
|
11
|
+
MDQxMzBiMTg4OGQ4YzM1YmJjZDcxM2MxYWY5OTZlNTdkYjg1ZWI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
N2EzZjE5OTNlN2YzZmNjMTAwNDE2YTU5NGYxMjFlN2JkMDE1OTJkMjVjNjBl
|
14
|
+
ODQ4YjY0MzI5YWFjYjgxYzg4ZDQ4ZTQ1YWM3OTljY2FlMzllYWZjZTk3ZTZi
|
15
|
+
N2RiNDBlN2EyMjY4ODM0YjU0ZDgxZThjMzM3MTk4MzdhM2VjMmY=
|
data/CHANGELOG.markdown
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
Changelog
|
2
2
|
=========
|
3
3
|
|
4
|
+
0.0.5
|
5
|
+
-----
|
6
|
+
|
7
|
+
Removed Reloadable and Hooks patterns.
|
8
|
+
Added `get_and_set_block()` to GetAndSet (declares or runs a block)
|
9
|
+
`get_and_set*()` methods can now be called in `Class` and `Module` themselves.
|
10
|
+
|
4
11
|
0.0.4
|
5
12
|
-----
|
6
13
|
|
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -63,9 +63,63 @@ For each directory you give it, it will:
|
|
63
63
|
|
64
64
|
You can get some interesting behavior by overwriting individual methods. For example, loading individual configurations from YAML or JSON or XML. There's an example in the test/ folder.
|
65
65
|
|
66
|
+
The default "style" of loading a file is "eval the contents and return the result." This may not always be the desired behavior. Other built in loading styles:
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
|
66
72
|
Note: If you want to manage your own registry by redefining loader_pattern_load_from_dir( dir ), loader_pattern_register_item( item ), etc., make sure you handle and report exceptions.
|
67
73
|
|
68
74
|
|
75
|
+
More example code!
|
76
|
+
|
77
|
+
class Klass
|
78
|
+
|
79
|
+
include FunWith::Patterns::Loader
|
80
|
+
loader_pattern_configure( :bracketwise_lookup,
|
81
|
+
:warn_on_key_change,
|
82
|
+
{ :verbose => true, :load } )
|
83
|
+
end
|
84
|
+
|
85
|
+
loader_pattern_configure is a quickie method for setting up a variety of behaviors. Options so far:
|
86
|
+
|
87
|
+
:bracketwise_lookup : instead of calling Klass.loader_pattern_registry_lookup( "string" )
|
88
|
+
you can just call Klass["string"]
|
89
|
+
|
90
|
+
{:key => :<sym>} : loader determines registry key by calling this method
|
91
|
+
|
92
|
+
:warn_on_key_changes : If a newly loaded item has an existing registry key, it prints a warning as it overwrites
|
93
|
+
|
94
|
+
:dont_warn_on_key_changes : (default)
|
95
|
+
:style => :(eval|instance_exec|yaml) : Use one of the built-in loading styles. Otherwise, set custom loading
|
96
|
+
behavior by defining your own Klass.loader_pattern_register_item
|
97
|
+
|
98
|
+
|
99
|
+
The styles need some explanation:
|
100
|
+
|
101
|
+
:eval (default) : evals the contents of the file and returns the result
|
102
|
+
|
103
|
+
:instance_exec : The file contents will run as though inside the object
|
104
|
+
|
105
|
+
Klass.new do
|
106
|
+
# ----- file contents for boris.rb starts here
|
107
|
+
self.name "Boris"
|
108
|
+
self.age 23
|
109
|
+
self.kill_count 9
|
110
|
+
# ----- file contents for boris.rb end here
|
111
|
+
end
|
112
|
+
|
113
|
+
:yaml The file contents describe a YAML hash, with the topmost keys describing
|
114
|
+
the setter to call in order to set the attribute to that value. For example,
|
115
|
+
|
116
|
+
---
|
117
|
+
- name: Boris
|
118
|
+
|
119
|
+
would end up calling klass_object.name=( "Boris" )
|
120
|
+
|
121
|
+
|
122
|
+
TODO: I feel like a default label should maybe come out of the filename (zero-config and all that), but haven't built it.
|
69
123
|
|
70
124
|
== Reloadable ==
|
71
125
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.5
|
@@ -17,8 +17,7 @@ module FunWith
|
|
17
17
|
end
|
18
18
|
|
19
19
|
# Would also like to do a boolean version which creates
|
20
|
-
# .bool? .bool! and .not_bool!
|
21
|
-
|
20
|
+
# .bool? .bool! and .not_bool!
|
22
21
|
def get_and_set_boolean( *method_names )
|
23
22
|
for name in method_names
|
24
23
|
if self.is_a?(Class) || self.is_a?(Module)
|
@@ -45,6 +44,21 @@ module FunWith
|
|
45
44
|
end
|
46
45
|
end
|
47
46
|
end
|
47
|
+
|
48
|
+
# the name() method can be called with a block (to change the block that is to be executed)
|
49
|
+
# or called with args to get the results of the block. Uses the internal object variable @name
|
50
|
+
def get_and_set_block( name, *args, &block )
|
51
|
+
eval "define_method( :#{name} ) do |*args, &block|
|
52
|
+
if block.is_a?( Proc ) # oddly, block_given? always returns false when defined this way
|
53
|
+
raise ArgumentError.new( 'Call #{name}() with either a block or args' ) unless args.length == 0
|
54
|
+
self.instance_variable_set( :@#{name}, block )
|
55
|
+
block
|
56
|
+
else
|
57
|
+
block = self.instance_variable_get( :@#{name} )
|
58
|
+
( block || Proc.new{} ).call( *args )
|
59
|
+
end
|
60
|
+
end "
|
61
|
+
end
|
48
62
|
end
|
49
63
|
end
|
50
64
|
end
|
@@ -1,11 +1,20 @@
|
|
1
1
|
module FunWith
|
2
2
|
module Patterns
|
3
3
|
module GetAndSetAPI
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
# Can pass in an array listing the classes to activate, or just pass in arguments
|
5
|
+
def activate( *classes_to_activate )
|
6
|
+
if classes_to_activate.length == 1 && classes_to_activate.first.is_a?(Array)
|
7
|
+
classes_to_activate = classes_to_activate.first
|
8
|
+
elsif classes_to_activate.length == 0
|
9
|
+
classes_to_activate = [Class, Module] # no arguments given
|
10
|
+
end
|
11
|
+
|
7
12
|
for klass in classes_to_activate
|
8
|
-
klass
|
13
|
+
if klass == Class || klass == Module
|
14
|
+
klass.send( :include, GetAndSet ) # Because individual classes or modules are objects of class Class/Module
|
15
|
+
end
|
16
|
+
|
17
|
+
klass.send( :extend, GetAndSet )
|
9
18
|
end
|
10
19
|
end
|
11
20
|
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
module FunWith
|
2
|
+
module Patterns
|
3
|
+
module Loader
|
4
|
+
module ClassMethods
|
5
|
+
# By default, looks for .rb files to evaluate
|
6
|
+
# ext => :all (or "*") to load every file from directory.
|
7
|
+
# ext => :rb (or "rb") to load all .rb files (this is default)
|
8
|
+
# call without arguments to inquire about current extension.
|
9
|
+
def loader_pattern_extension( ext = nil )
|
10
|
+
case ext
|
11
|
+
when nil
|
12
|
+
# do nothing
|
13
|
+
when "*", :all
|
14
|
+
@loader_pattern_extension = "*"
|
15
|
+
else
|
16
|
+
@loader_pattern_extension = ext
|
17
|
+
end
|
18
|
+
|
19
|
+
@loader_pattern_extension
|
20
|
+
end
|
21
|
+
|
22
|
+
def loader_pattern_verbose( verbosity = nil )
|
23
|
+
@loader_pattern_verbose = verbosity unless verbosity.nil?
|
24
|
+
@loader_pattern_verbose
|
25
|
+
end
|
26
|
+
|
27
|
+
def loader_pattern_rescue_failing_item_load( file, &block )
|
28
|
+
file = file.fwf_filepath.expand
|
29
|
+
if file.file?
|
30
|
+
obj = yield
|
31
|
+
STDOUT.puts( "Loaded file #{file}" ) if self.loader_pattern_verbose
|
32
|
+
|
33
|
+
obj
|
34
|
+
else
|
35
|
+
STDERR.puts( "(#{self.class}) Load failed, no such file: #{file}" )
|
36
|
+
end
|
37
|
+
rescue Exception => e
|
38
|
+
STDERR.puts( "Could not load file #{file}. Reason: #{e.class.name} #{e.message}" )
|
39
|
+
|
40
|
+
if self.loader_pattern_verbose
|
41
|
+
STDERR.puts( puts e.backtrace.map{|line| "\t\t#{line}"}.join("\n") )
|
42
|
+
STDERR.puts( "\n" )
|
43
|
+
end
|
44
|
+
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
|
48
|
+
# Default, may want to override how the registry behaves.
|
49
|
+
# If you don't provide a key argument, then the object needs to
|
50
|
+
# respond to .loader_pattern_registry_key()
|
51
|
+
def loader_pattern_register_item( obj, key = nil )
|
52
|
+
return nil if obj.nil?
|
53
|
+
@loader_pattern_registry ||= {}
|
54
|
+
|
55
|
+
if key.nil?
|
56
|
+
if obj.respond_to?( :loader_pattern_registry_key )
|
57
|
+
key = obj.loader_pattern_registry_key
|
58
|
+
else
|
59
|
+
raise "#{self.class} not registered. No registry key given, and object does not respond to .loader_pattern_registry_key()."
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
if loader_pattern_is_item_registerable?( obj )
|
64
|
+
if @loader_pattern_warn_on_key_changes && loader_pattern_registry_lookup( key )
|
65
|
+
warn( "class #{self} is replacing lookup key #{key.inspect}" )
|
66
|
+
end
|
67
|
+
|
68
|
+
return @loader_pattern_registry[ key ] = obj
|
69
|
+
else
|
70
|
+
warn( "#{obj} is not an instance of a registerable class. Registerable classes: #{self.loader_pattern_only_register_classes.inspect}" )
|
71
|
+
return nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def loader_pattern_registry_lookup( key )
|
76
|
+
@loader_pattern_registry ||= {}
|
77
|
+
@loader_pattern_registry[key]
|
78
|
+
end
|
79
|
+
|
80
|
+
def loader_pattern_registry
|
81
|
+
@loader_pattern_registry
|
82
|
+
end
|
83
|
+
|
84
|
+
def loader_pattern_only_register_classes( *args )
|
85
|
+
if args.length > 0
|
86
|
+
@loader_pattern_only_register_classes = args
|
87
|
+
end
|
88
|
+
|
89
|
+
@loader_pattern_only_register_classes || []
|
90
|
+
end
|
91
|
+
|
92
|
+
def loader_pattern_is_item_registerable?( item )
|
93
|
+
return true if loader_pattern_only_register_classes.fwf_blank?
|
94
|
+
|
95
|
+
for klass in @loader_pattern_only_register_classes
|
96
|
+
return true if item.is_a?( klass )
|
97
|
+
end
|
98
|
+
|
99
|
+
return false
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
# Assumes that every file in the directory and subdirectories contain ruby code that
|
104
|
+
# will yield an object that the loader is looking for. It also automatically
|
105
|
+
# adds the resulting object to a registry.
|
106
|
+
# You may want to override this if you're looking for different behavior.
|
107
|
+
def loader_pattern_load_from_dir( *dirs )
|
108
|
+
for dir in dirs
|
109
|
+
dir = dir.fwf_filepath
|
110
|
+
@loader_pattern_directories ||= []
|
111
|
+
@loader_pattern_directories << dir
|
112
|
+
|
113
|
+
for file in dir.glob( :ext => self.loader_pattern_extension, :recurse => true )
|
114
|
+
obj = self.loader_pattern_load_item( file )
|
115
|
+
self.loader_pattern_register_item( obj ) if self.loader_pattern_is_item_registerable?( obj )
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def loader_pattern_loaded_directories
|
121
|
+
@loader_pattern_directories ||= []
|
122
|
+
end
|
123
|
+
|
124
|
+
# Handle the initial configuration of the class.
|
125
|
+
#
|
126
|
+
# :bracketwise_lookup : Instead of looking up an object by LoaderBearingClass.loader_pattern_registry_lookup(:keyword)
|
127
|
+
# you can simply use LoaderBearingClass[:keyword]
|
128
|
+
#
|
129
|
+
# :warn_on_key_changes : Warns whenever the registry overwrites an existing key. Useful for debugging, sometimes.
|
130
|
+
#
|
131
|
+
# Some configuration directives are given as hashes. Multiple directives may be combined into
|
132
|
+
# a single hash.
|
133
|
+
#
|
134
|
+
# {:key => <METHOD_SYM>} : The method for asking the object what name it should be lookupable under.
|
135
|
+
#
|
136
|
+
# {:verbose => (true|false)} : How noisy do you want the loading to be?
|
137
|
+
#
|
138
|
+
# {:style => :eval}
|
139
|
+
#
|
140
|
+
# {:style => :instance_exec}
|
141
|
+
#
|
142
|
+
# {:style => <PROC>}
|
143
|
+
|
144
|
+
def loader_pattern_configure( *args )
|
145
|
+
for arg in args
|
146
|
+
case arg
|
147
|
+
when :bracketwise_lookup
|
148
|
+
self.extend( Features::BracketwiseLookup )
|
149
|
+
when :warn_on_key_changes
|
150
|
+
@loader_pattern_warn_on_key_changes = true
|
151
|
+
when :dont_warn_on_key_changes
|
152
|
+
@loader_pattern_warn_on_key_changes = false
|
153
|
+
when Hash
|
154
|
+
for key, val in arg
|
155
|
+
case key
|
156
|
+
when :key
|
157
|
+
self.class_eval do
|
158
|
+
eval( "alias :loader_pattern_registry_key #{val.to_sym.inspect}" )
|
159
|
+
end
|
160
|
+
when :verbose
|
161
|
+
self.loader_pattern_verbose( val )
|
162
|
+
when :style
|
163
|
+
case val # styles allowed: :eval, :instance_exec
|
164
|
+
when :eval
|
165
|
+
self.extend( LoadingStyles::Eval )
|
166
|
+
when :instance_exec
|
167
|
+
self.extend( LoadingStyles::InstanceExec )
|
168
|
+
when :yaml
|
169
|
+
self.extend( LoadingStyles::YAML )
|
170
|
+
self.loader_pattern_extension( [:yml, :yaml] )
|
171
|
+
else
|
172
|
+
raise "Unknown Loader loading style: #{val.inspect}"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module FunWith
|
2
|
+
module Patterns
|
3
|
+
module Loader
|
4
|
+
module Features
|
5
|
+
module BracketwiseLookup
|
6
|
+
def []( key )
|
7
|
+
loader_pattern_registry_lookup( key )
|
8
|
+
end
|
9
|
+
|
10
|
+
def []=( key, val )
|
11
|
+
loader_pattern_register_item( val, key )
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module FunWith
|
2
|
+
module Patterns
|
3
|
+
module Loader
|
4
|
+
module LoadingStyles
|
5
|
+
module Eval
|
6
|
+
# Default behavior: read the file, evaluate it, expect a ruby object
|
7
|
+
# of the class that the loader pattern is installed on. If anything goes
|
8
|
+
# wrong (file no exist, syntax error), returns a nil.
|
9
|
+
#
|
10
|
+
# Override in your class if you need your files translated
|
11
|
+
# into objects differently.
|
12
|
+
def loader_pattern_load_item( file )
|
13
|
+
self.loader_pattern_rescue_failing_item_load( file ) do
|
14
|
+
obj = eval( file.read )
|
15
|
+
|
16
|
+
return obj
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module FunWith
|
2
|
+
module Patterns
|
3
|
+
module Loader
|
4
|
+
module LoadingStyles
|
5
|
+
# Assumes the class does not take arguments in its initialize() method.
|
6
|
+
# The contents of the file are run via instance_exec to configure the object.
|
7
|
+
module InstanceExec
|
8
|
+
def loader_pattern_load_item( file )
|
9
|
+
self.loader_pattern_rescue_failing_item_load( file ) do
|
10
|
+
obj = self.new
|
11
|
+
|
12
|
+
# obj.instance_eval( file.read )
|
13
|
+
obj.instance_exec do
|
14
|
+
eval( file.read )
|
15
|
+
end
|
16
|
+
|
17
|
+
return obj
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module FunWith
|
2
|
+
module Patterns
|
3
|
+
module Loader
|
4
|
+
module LoadingStyles
|
5
|
+
module YAML
|
6
|
+
def loader_pattern_load_item( file )
|
7
|
+
self.loader_pattern_rescue_failing_item_load( file ) do
|
8
|
+
obj = self.new
|
9
|
+
|
10
|
+
hash = Psych.load( file.read )
|
11
|
+
|
12
|
+
for method, val in hash
|
13
|
+
eq_method = :"#{method}="
|
14
|
+
|
15
|
+
if obj.respond_to?( eq_method )
|
16
|
+
obj.send( eq_method, val )
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
return obj
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -3,161 +3,8 @@ module FunWith
|
|
3
3
|
module Loader
|
4
4
|
def self.included( base )
|
5
5
|
base.extend( ClassMethods )
|
6
|
-
base.
|
7
|
-
|
8
|
-
|
9
|
-
module ClassMethods
|
10
|
-
# By default, looks for .rb files to evaluate
|
11
|
-
# ext => :all (or "*") to load every file from directory.
|
12
|
-
# ext => :rb (or "rb") to load all .rb files (this is default)
|
13
|
-
# call without arguments to inquire about current extension.
|
14
|
-
def loader_pattern_extension( ext = nil )
|
15
|
-
case ext
|
16
|
-
when nil
|
17
|
-
# do nothing
|
18
|
-
when "*", :all
|
19
|
-
@loader_pattern_extension = "*"
|
20
|
-
else
|
21
|
-
@loader_pattern_extension = "*.#{ext}"
|
22
|
-
end
|
23
|
-
|
24
|
-
@loader_pattern_extension
|
25
|
-
end
|
26
|
-
|
27
|
-
def loader_pattern_verbose( verbosity = nil )
|
28
|
-
@loader_pattern_verbose = verbosity unless verbosity.nil?
|
29
|
-
@loader_pattern_verbose
|
30
|
-
end
|
31
|
-
|
32
|
-
# Default behavior: read the file, evaluate it, expect a ruby object
|
33
|
-
# of the class that the loader pattern is installed on. If anything goes
|
34
|
-
# wrong (file no exist, syntax error), returns a nil.
|
35
|
-
#
|
36
|
-
# Override in your class if you need your files translated
|
37
|
-
# into objects differently.
|
38
|
-
def loader_pattern_load_item( file )
|
39
|
-
file = file.fwf_filepath
|
40
|
-
if file.file?
|
41
|
-
obj = eval( file.read )
|
42
|
-
|
43
|
-
STDOUT.puts( "Loaded file #{file}" ) if self.loader_pattern_verbose
|
44
|
-
return obj
|
45
|
-
else
|
46
|
-
STDERR.puts( "(#{self.class}) Load failed, no such file: #{file}" )
|
47
|
-
return nil
|
48
|
-
end
|
49
|
-
rescue Exception => e
|
50
|
-
STDERR.puts( "Could not load file #{file}. Reason: #{e.class.name} #{e.message}" )
|
51
|
-
|
52
|
-
if self.loader_pattern_verbose
|
53
|
-
STDERR.puts( puts e.backtrace.map{|line| "\t\t#{line}"}.join("\n") )
|
54
|
-
STDERR.puts( "\n" )
|
55
|
-
end
|
56
|
-
|
57
|
-
nil
|
58
|
-
end
|
59
|
-
|
60
|
-
# Default, may want to override how the registry behaves.
|
61
|
-
# If you don't provide a key argument, then the object needs to
|
62
|
-
# respond to .loader_pattern_registry_key()
|
63
|
-
def loader_pattern_register_item( obj, key = nil )
|
64
|
-
return nil if obj.nil?
|
65
|
-
@loader_pattern_registry ||= {}
|
66
|
-
|
67
|
-
key = obj.loader_pattern_registry_key if key.nil?
|
68
|
-
|
69
|
-
if loader_pattern_is_item_registerable?( obj )
|
70
|
-
if @loader_pattern_warn_on_key_changes && loader_pattern_registry_lookup( key )
|
71
|
-
warn( "class #{self} is replacing lookup key #{key.inspect}" )
|
72
|
-
end
|
73
|
-
|
74
|
-
return @loader_pattern_registry[ key ] = obj
|
75
|
-
else
|
76
|
-
warn( "#{obj} is not an instance of a registerable class. Registerable classes: #{self.loader_pattern_only_register_classes.inspect}" )
|
77
|
-
return nil
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def loader_pattern_registry_lookup( key )
|
82
|
-
@loader_pattern_registry ||= {}
|
83
|
-
@loader_pattern_registry[key]
|
84
|
-
end
|
85
|
-
|
86
|
-
def loader_pattern_registry
|
87
|
-
@loader_pattern_registry
|
88
|
-
end
|
89
|
-
|
90
|
-
def loader_pattern_only_register_classes( *args )
|
91
|
-
if args.length > 0
|
92
|
-
@loader_pattern_only_register_classes = args
|
93
|
-
end
|
94
|
-
|
95
|
-
@loader_pattern_only_register_classes || []
|
96
|
-
end
|
97
|
-
|
98
|
-
def loader_pattern_is_item_registerable?( item )
|
99
|
-
return true if loader_pattern_only_register_classes.fwf_blank?
|
100
|
-
|
101
|
-
for klass in @loader_pattern_only_register_classes
|
102
|
-
return true if item.is_a?( klass )
|
103
|
-
end
|
104
|
-
|
105
|
-
return false
|
106
|
-
end
|
107
|
-
|
108
|
-
|
109
|
-
# Assumes that every file in the directory and subdirectories contain ruby code that
|
110
|
-
# will yield an object that the loader is looking for. It also automatically
|
111
|
-
# adds the resulting object to a registry.
|
112
|
-
# You may want to override this if you're looking for different behavior.
|
113
|
-
def loader_pattern_load_from_dir( *dirs )
|
114
|
-
for dir in dirs
|
115
|
-
dir = dir.fwf_filepath
|
116
|
-
@loader_pattern_directories ||= []
|
117
|
-
@loader_pattern_directories << dir
|
118
|
-
|
119
|
-
for file in dir.glob( "**", self.loader_pattern_extension )
|
120
|
-
obj = self.loader_pattern_load_item( file )
|
121
|
-
self.loader_pattern_register_item( obj ) if self.loader_pattern_is_item_registerable?( obj )
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
def loader_pattern_loaded_directories
|
127
|
-
@loader_pattern_directories ||= []
|
128
|
-
end
|
129
|
-
|
130
|
-
def loader_pattern_configure( *args )
|
131
|
-
for arg in args
|
132
|
-
case arg
|
133
|
-
when :bracketwise_lookup
|
134
|
-
self.class_eval do
|
135
|
-
def self.[]( key )
|
136
|
-
loader_pattern_registry_lookup( key )
|
137
|
-
end
|
138
|
-
|
139
|
-
def self.[]=( key, val )
|
140
|
-
loader_pattern_register_item( val, key )
|
141
|
-
end
|
142
|
-
end
|
143
|
-
when :warn_on_key_changes
|
144
|
-
@loader_pattern_warn_on_key_changes = true
|
145
|
-
when :dont_warn_on_key_changes
|
146
|
-
@loader_pattern_warn_on_key_changes = false
|
147
|
-
when Hash
|
148
|
-
for key, val in arg
|
149
|
-
case key
|
150
|
-
when :key
|
151
|
-
self.class_eval do
|
152
|
-
eval( "alias :loader_pattern_registry_key #{val.inspect}" )
|
153
|
-
end
|
154
|
-
when :verbose
|
155
|
-
self.loader_pattern_verbose( val )
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
6
|
+
base.extend( LoadingStyles::Eval ) # provides a default load_item method
|
7
|
+
base.loader_pattern_extension( :rb ) if base.loader_pattern_extension.nil?
|
161
8
|
end
|
162
9
|
end
|
163
10
|
end
|
data/lib/fun_with_patterns.rb
CHANGED
@@ -2,9 +2,7 @@ require 'fun_with_gems'
|
|
2
2
|
|
3
3
|
FunWith::Gems.make_gem_fun( "FunWith::Patterns" )
|
4
4
|
|
5
|
-
Class.send( :include, FunWith::Patterns::MakeInstancesReloadable )
|
6
|
-
Module.send( :include, FunWith::Patterns::MakeInstancesReloadable )
|
7
|
-
FunWith::Patterns::Reloadable.extend( FunWith::Patterns::ClassReloaderMethod )
|
8
5
|
|
9
6
|
# Activate Object#get_and_set / Module#get_and_set by calling GetAndSet.activate
|
10
|
-
FunWith::Patterns::GetAndSet.extend( FunWith::Patterns::GetAndSetAPI )
|
7
|
+
FunWith::Patterns::GetAndSet.extend( FunWith::Patterns::GetAndSetAPI )
|
8
|
+
|
data/test/helper.rb
CHANGED
@@ -15,8 +15,9 @@
|
|
15
15
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
16
16
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
17
17
|
|
18
|
-
require 'fun_with_testing'
|
19
18
|
require 'fun_with_patterns'
|
19
|
+
require 'fun_with_testing'
|
20
|
+
|
20
21
|
|
21
22
|
require_relative 'user'
|
22
23
|
require_relative 'yaml_obj'
|
data/test/test_get_and_set.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
|
-
FunWith::Patterns::GetAndSet.activate
|
4
|
-
|
5
3
|
class TestGetAndSet < FunWith::Patterns::TestCase
|
6
4
|
context "basics" do
|
7
5
|
should "be plumbed correctly" do
|
@@ -12,6 +10,8 @@ class TestGetAndSet < FunWith::Patterns::TestCase
|
|
12
10
|
context "trial run" do
|
13
11
|
should "get and set" do
|
14
12
|
c = Class.new
|
13
|
+
FunWith::Patterns::GetAndSet.activate( c )
|
14
|
+
|
15
15
|
c.get_and_set( :radio, :radius, :radium )
|
16
16
|
c.get_and_set( :radiate )
|
17
17
|
c.get_and_set_boolean( :stringy, :flurmish )
|
@@ -46,6 +46,8 @@ class TestGetAndSet < FunWith::Patterns::TestCase
|
|
46
46
|
m = Module.new
|
47
47
|
c = Class.new
|
48
48
|
|
49
|
+
FunWith::Patterns::GetAndSet.activate( m )
|
50
|
+
|
49
51
|
c.send( :include, m )
|
50
52
|
|
51
53
|
m.get_and_set( :radio, :radius, :radium )
|
@@ -73,5 +75,32 @@ class TestGetAndSet < FunWith::Patterns::TestCase
|
|
73
75
|
assert_equal v2, o.radium( v2 ) # ==> "Madame Curie"
|
74
76
|
assert_equal v2, o.radium() # ==> "Madame Curie"
|
75
77
|
end
|
78
|
+
|
79
|
+
should "get and set blocks" do
|
80
|
+
c = Class.new
|
81
|
+
FunWith::Patterns::GetAndSet.activate( c )
|
82
|
+
c.get_and_set_block( :string_transformation )
|
83
|
+
|
84
|
+
doubler = c.new
|
85
|
+
assert_respond_to( doubler, :string_transformation )
|
86
|
+
|
87
|
+
assert_nil doubler.string_transformation( "hello" )
|
88
|
+
|
89
|
+
doubler.string_transformation do |input|
|
90
|
+
"#{input}#{input}"
|
91
|
+
end
|
92
|
+
|
93
|
+
assert_equal "hellohello", doubler.string_transformation( "hello" )
|
94
|
+
assert_equal "55", doubler.string_transformation( "5" )
|
95
|
+
|
96
|
+
stripper = c.new
|
97
|
+
stripper.string_transformation do |input|
|
98
|
+
input.strip
|
99
|
+
end
|
100
|
+
|
101
|
+
assert_equal "stripped", stripper.string_transformation( " stripped ")
|
102
|
+
|
103
|
+
|
104
|
+
end
|
76
105
|
end
|
77
106
|
end
|
data/test/test_loader_pattern.rb
CHANGED
@@ -11,8 +11,12 @@ class TestLoaderPattern < FunWith::Patterns::TestCase
|
|
11
11
|
|
12
12
|
context "testing User" do
|
13
13
|
setup do
|
14
|
-
User.loader_pattern_load_from_dir( FunWith::Patterns.root( "test", "users" ) )
|
15
|
-
User2.loader_pattern_load_from_dir( FunWith::Patterns.root( "test", "users" ) )
|
14
|
+
User.loader_pattern_load_from_dir( FunWith::Patterns.root( "test", "users", "eval" ) )
|
15
|
+
User2.loader_pattern_load_from_dir( FunWith::Patterns.root( "test", "users", "eval" ) )
|
16
|
+
User3.loader_pattern_load_from_dir( FunWith::Patterns.root( "test", "users", "instance_exec" ) )
|
17
|
+
User4.loader_pattern_load_from_dir( FunWith::Patterns.root( "test", "users", "yaml" ) )
|
18
|
+
|
19
|
+
@user_classes = [User, User2, User3, User4]
|
16
20
|
end
|
17
21
|
|
18
22
|
should "have all the right methods" do
|
@@ -22,13 +26,17 @@ class TestLoaderPattern < FunWith::Patterns::TestCase
|
|
22
26
|
:loader_pattern_register_item,
|
23
27
|
:loader_pattern_load_from_dir,
|
24
28
|
:loader_pattern_configure ]
|
25
|
-
|
29
|
+
for klass in @user_classes
|
30
|
+
assert_respond_to( klass, method, "#{klass} should respond to ##{method}" )
|
31
|
+
end
|
26
32
|
end
|
27
33
|
end
|
28
34
|
|
29
|
-
should "load users from test/users
|
30
|
-
|
31
|
-
|
35
|
+
should "load users from test/users into various classes" do
|
36
|
+
for klass in @user_classes
|
37
|
+
assert klass.loader_pattern_registry_lookup("Gary Milhouse"), "#{klass} did not load Gary. Poor Gary."
|
38
|
+
assert_equal 54, klass.loader_pattern_registry_lookup("Gary Milhouse").age, "#{klass} did not load Gary with proper age data."
|
39
|
+
end
|
32
40
|
end
|
33
41
|
|
34
42
|
should "lookup via brackets" do
|
data/test/user.rb
CHANGED
@@ -22,4 +22,28 @@ class User2
|
|
22
22
|
@name = name
|
23
23
|
@age = age
|
24
24
|
end
|
25
|
-
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class User3
|
28
|
+
FunWith::Patterns::GetAndSet.activate( self )
|
29
|
+
|
30
|
+
get_and_set :name, :age
|
31
|
+
|
32
|
+
include FunWith::Patterns::Loader
|
33
|
+
loader_pattern_configure( :bracketwise_lookup,
|
34
|
+
{ :key => :name },
|
35
|
+
{ :style => :instance_exec } # Create object, run code in configuration file inside the object's context.
|
36
|
+
)
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
class User4
|
41
|
+
attr_accessor :name, :age
|
42
|
+
|
43
|
+
include FunWith::Patterns::Loader
|
44
|
+
loader_pattern_configure( :bracketwise_lookup,
|
45
|
+
{ :key => :name },
|
46
|
+
{ :style => :yaml }
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/test/yaml_obj.rb
CHANGED
metadata
CHANGED
@@ -1,19 +1,22 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fun_with_patterns
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bryce Anderson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fun_with_gems
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.0.2
|
17
20
|
- - ~>
|
18
21
|
- !ruby/object:Gem::Version
|
19
22
|
version: '0.0'
|
@@ -21,6 +24,9 @@ dependencies:
|
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.0.2
|
24
30
|
- - ~>
|
25
31
|
- !ruby/object:Gem::Version
|
26
32
|
version: '0.0'
|
@@ -48,21 +54,29 @@ extra_rdoc_files:
|
|
48
54
|
files:
|
49
55
|
- ./lib/fun_with/patterns/get_and_set.rb
|
50
56
|
- ./lib/fun_with/patterns/get_and_set_api.rb
|
51
|
-
- ./lib/fun_with/patterns/hooks.rb
|
52
57
|
- ./lib/fun_with/patterns/loader.rb
|
53
|
-
- ./lib/fun_with/patterns/
|
58
|
+
- ./lib/fun_with/patterns/loader/class_methods.rb
|
59
|
+
- ./lib/fun_with/patterns/loader/features/bracketwise_lookup.rb
|
60
|
+
- ./lib/fun_with/patterns/loader/loading_styles/eval.rb
|
61
|
+
- ./lib/fun_with/patterns/loader/loading_styles/instance_exec.rb
|
62
|
+
- ./lib/fun_with/patterns/loader/loading_styles/yaml.rb
|
54
63
|
- ./lib/fun_with_patterns.rb
|
55
64
|
- ./test/helper.rb
|
56
|
-
- ./test/reloadable/my_reloadable.rb
|
57
65
|
- ./test/test_get_and_set.rb
|
58
|
-
- ./test/test_hooks.rb
|
59
66
|
- ./test/test_loader_pattern.rb
|
60
|
-
- ./test/test_reloadable_pattern.rb
|
61
67
|
- ./test/user.rb
|
62
|
-
- ./test/users/mary.rb
|
63
|
-
- ./test/users/more/gary.rb
|
64
|
-
- ./test/users/steve.rb
|
65
|
-
- ./test/users/wanda.rb
|
68
|
+
- ./test/users/eval/mary.rb
|
69
|
+
- ./test/users/eval/more/gary.rb
|
70
|
+
- ./test/users/eval/steve.rb
|
71
|
+
- ./test/users/eval/wanda.rb
|
72
|
+
- ./test/users/instance_exec/mary.rb
|
73
|
+
- ./test/users/instance_exec/more/gary.rb
|
74
|
+
- ./test/users/instance_exec/steve.rb
|
75
|
+
- ./test/users/instance_exec/wanda.rb
|
76
|
+
- ./test/users/yaml/mary.yaml
|
77
|
+
- ./test/users/yaml/more/gary.yml
|
78
|
+
- ./test/users/yaml/steve.yaml
|
79
|
+
- ./test/users/yaml/wanda.yml
|
66
80
|
- ./test/yaml_obj.rb
|
67
81
|
- ./test/yamls/mike/mike_amazon.yaml
|
68
82
|
- ./test/yamls/mike/mike_gmail.yaml
|
@@ -1,47 +0,0 @@
|
|
1
|
-
module FunWith
|
2
|
-
module Patterns
|
3
|
-
module Hooks
|
4
|
-
def add_hook_before( method, &block )
|
5
|
-
hook_pattern_install_hooks_for_method( method )
|
6
|
-
end
|
7
|
-
|
8
|
-
def add_hook_after( method, &block )
|
9
|
-
hook_pattern_install_hooks_for_method( method )
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
def hook_pattern_hooks_installed_for_method?( method )
|
14
|
-
self.respond_to?( :"#{method}_method_without_hooks" )
|
15
|
-
end
|
16
|
-
|
17
|
-
def hook_pattern_install_hooks_for_method( method )
|
18
|
-
return false if hook_pattern_hooks_installed_for_method?( method )
|
19
|
-
|
20
|
-
alias :"#{method}_method_without_hooks" :"#{method}"
|
21
|
-
|
22
|
-
@hook_pattern_hooks ||= {}
|
23
|
-
@hook_pattern_hooks[method] ||= {}
|
24
|
-
@hook_pattern_hooks[method][:before] ||= []
|
25
|
-
@hook_pattern_hooks[method][:after] ||= []
|
26
|
-
|
27
|
-
|
28
|
-
# http://stackoverflow.com/questions/4470108/when-monkey-patching-a-method-can-you-call-the-overridden-method-from-the-new-i
|
29
|
-
old_method = instance_method(method)
|
30
|
-
|
31
|
-
# define_method(:bar) do
|
32
|
-
# old_bar.bind(self).() + ' World'
|
33
|
-
# end
|
34
|
-
|
35
|
-
define_method( method ) do |*args, &block|
|
36
|
-
self.hook_pattern_run( @hook_pattern_hooks[method][:before], *args, &block )
|
37
|
-
old_method.bind( self ).call( *args, &block )
|
38
|
-
self.hook_pattern_run( @hook_pattern_hooks[method][:after], *args, &block )
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def hook_pattern_run( hookset, *args, &block )
|
43
|
-
puts "running hookset"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
warn( "Something wrong with the Reloadable class. Flaky. Not recommended for use." )
|
2
|
-
module FunWith
|
3
|
-
module Patterns
|
4
|
-
# A bare-bones reloading system. Useful when the entire file defines exactly one
|
5
|
-
# class or module, with no dependencies or side-effects.
|
6
|
-
module Reloadable
|
7
|
-
def reload!
|
8
|
-
FunWith::Patterns::Reloadable.reload_class( self )
|
9
|
-
end
|
10
|
-
|
11
|
-
def reloader_filepath
|
12
|
-
@reloader_filepath
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
module MakeInstancesReloadable
|
17
|
-
def reloadable!
|
18
|
-
self.extend( FunWith::Patterns::Reloadable )
|
19
|
-
kaller = caller.first.gsub(/:\d+:in.*/, '')
|
20
|
-
@reloader_filepath = kaller.fwf_filepath.expand
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
module ClassReloaderMethod
|
25
|
-
def reload_class( klass )
|
26
|
-
if file = klass.reloader_filepath
|
27
|
-
Object.send( :remove_const, klass.name.to_sym )
|
28
|
-
file.load
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
data/test/test_hooks.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class TestHooksPattern < FunWith::Patterns::TestCase
|
4
|
-
_context "first try" do
|
5
|
-
should "set up a class with hooks" do
|
6
|
-
class A
|
7
|
-
include FunWith::Patterns::Hooks
|
8
|
-
|
9
|
-
def called_x_times()
|
10
|
-
@called_x_times ||= 0
|
11
|
-
@called_x_times
|
12
|
-
end
|
13
|
-
|
14
|
-
add_hook_before( :called_x_times ) do
|
15
|
-
@called_x_times ||= 0
|
16
|
-
@called_x_times += 1
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
a = A.new
|
21
|
-
|
22
|
-
assert_one( a.called_x_times() )
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class TestReloadablePattern < FunWith::Patterns::TestCase
|
4
|
-
context "testing basics" do
|
5
|
-
setup do
|
6
|
-
Class.send( :include, FunWith::Patterns::Reloadable )
|
7
|
-
assert_has_instance_method( Class, :reload! )
|
8
|
-
assert_has_instance_method( Class, :reloadable! )
|
9
|
-
|
10
|
-
assert_respond_to( Object, :reload!)
|
11
|
-
assert_respond_to( Object, :reloadable!)
|
12
|
-
end
|
13
|
-
|
14
|
-
should "reload MyReloadable" do
|
15
|
-
refute defined?(MyReloadable)
|
16
|
-
FunWith::Patterns.root( "test", "reloadable", "my_reloadable.rb" ).requir
|
17
|
-
assert defined?(MyReloadable)
|
18
|
-
assert_respond_to( MyReloadable.new, :square )
|
19
|
-
|
20
|
-
MyReloadable.class_eval do
|
21
|
-
remove_method :square
|
22
|
-
end
|
23
|
-
|
24
|
-
refute_respond_to( MyReloadable.new, :square )
|
25
|
-
|
26
|
-
MyReloadable.reload!
|
27
|
-
|
28
|
-
assert defined?(MyReloadable)
|
29
|
-
|
30
|
-
assert_respond_to( MyReloadable.new, :square )
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|