filigree 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,159 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Filigree
3
+ # Date: 2013/05/04
4
+ # Description: Extensions to help with type checking.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Standard Library
11
+
12
+ # Filigree
13
+ require 'filigree/class_methods_module'
14
+
15
+ ###########
16
+ # Methods #
17
+ ###########
18
+
19
+ # A method for type checking Ruby values.
20
+ #
21
+ # @param [Object] obj Object to type check.
22
+ # @param [Class] type Class the object should be an instance of.
23
+ # @param [String, nil] blame Variable name to blame for failed type checks.
24
+ # @param [Boolean] nillable Object can be nil?
25
+ # @param [Boolean] strict Strict or non-strict checking. Uses `instance_of?` and `is_a?` respectively.
26
+ #
27
+ # @raise [ArgumentError] An error is raise if the type checking fails.
28
+ #
29
+ # @return [Object] The object passed as parameter o.
30
+ def check_type(obj, type, blame = nil, nillable = false, strict = false)
31
+ type_ok = if strict then obj.instance_of?(type) else obj.is_a?(type) end || (obj.nil? and nillable)
32
+
33
+ if type_ok
34
+ obj
35
+ else
36
+ if blame
37
+ raise TypeError,
38
+ "Parameter #{blame} must be an instance of the #{type.name} class. Received an instance of #{obj.class.name}."
39
+ else
40
+ raise TypeError,
41
+ "Expected an object of type #{type.name}. Received an instance of #{obj.class.name}."
42
+ end
43
+ end
44
+ end
45
+
46
+ # A method for type checking Ruby array values.
47
+ #
48
+ # @param [Array<Object>] array Array of objects to type check.
49
+ # @param [Class] type Class the objects should be an instance of.
50
+ # @param [String, nil] blame Variable name to blame for failed type checks.
51
+ # @param [Boolean] nillable Object can be nil?
52
+ # @param [Boolean] strict Strict or non-strict checking. Uses `instance_of?` and `is_a?` respectively.
53
+ #
54
+ # @raise [ArgumentError] An error is raise if the type checking fails.
55
+ #
56
+ # @return [Object] The object passed in parameter o.
57
+ def check_array_type(array, type, blame = nil, nillable = false, strict = false)
58
+ array.each do |obj|
59
+ type_ok = if strict then obj.instance_of?(type) else obj.is_a?(type) end || (obj.nil? and nillable)
60
+
61
+ if not type_ok
62
+ if blame
63
+ raise TypeError, "Parameter #{blame} must contain instances of the #{type.name} class."
64
+ else
65
+ raise TypeError, "Expected an object of type #{type.name}."
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ #######################
72
+ # Classes and Modules #
73
+ #######################
74
+
75
+ module Filigree
76
+ # Allows the including class to define typed type checked instance
77
+ # variables. This also provides a default constructor.
78
+ module TypedClass
79
+ include ClassMethodsModule
80
+
81
+ # Set each of the typed instance variables to its corresponding
82
+ # value.
83
+ #
84
+ # @param [Array<Object>] vals Values to set typed variables to
85
+ #
86
+ # @return [void]
87
+ def set_typed_ivars(vals)
88
+ self.class.typed_ivars.zip(vals).each do |name, val|
89
+ self.send("#{name}=", val)
90
+ end
91
+ end
92
+
93
+ module ClassMethods
94
+ # Define the default constructor for the including class.
95
+ #
96
+ # @param [Boolean] strict To use strict checking or not
97
+ #
98
+ # @return [void]
99
+ def default_constructor(strict = false)
100
+ class_eval do
101
+ if strict
102
+ def initialize(*vals)
103
+ if self.class.typed_ivars.length != vals.length
104
+ raise ArgumentError, "#{self.class.typed_ivars.length} arguments expected, #{vals.length} given."
105
+ end
106
+
107
+ self.set_typed_ivars(vals)
108
+ end
109
+ else
110
+ def initialize(*vals)
111
+ self.set_typed_ivars(vals)
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ # Define a new typed accessor.
118
+ #
119
+ # @param [Symbol] name Name of the accessor
120
+ # @param [Boolean] nillable If the value can be nil or not
121
+ # @param [Boolean] strict To use strict checking or not
122
+ # @param [Class] type Type of the accessor
123
+ # @param [Proc] checker Method used to check the type
124
+ #
125
+ # @return [void]
126
+ def define_typed_accessor(name, nillable, strict, type, checker)
127
+ define_method "#{name}=" do |obj|
128
+ self.instance_variable_set("@#{name}", checker.call(obj, type, name, nillable, strict))
129
+ end
130
+ end
131
+ private :define_typed_accessor
132
+
133
+ # Define a typed instance variable.
134
+ #
135
+ # @param [Symbol] name Name of the accessor
136
+ # @param [Class] type Type of the accessor
137
+ # @param [Boolean] nillable If the value can be nil or not
138
+ # @param [Boolean] strict To use strict checking or not
139
+ #
140
+ # @return [void]
141
+ def typed_ivar(name, type, nillable = false, strict = false)
142
+ typed_ivars << name
143
+
144
+ define_typed_accessor(name, nillable, strict, *
145
+ type.is_a?(Array) ? [type.first, method(:check_array_type)] : [type, method(:check_type)]
146
+ )
147
+
148
+ attr_reader name
149
+ end
150
+
151
+ # Return the typed instance variables for an object.
152
+ #
153
+ # @return [Array<Symbol>] Array of defined typed instance variables
154
+ def typed_ivars
155
+ @typed_ivars ||= Array.new
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,8 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Filigree
3
+ # Date: 2013/4/19
4
+ # Description: This file specifies the version number of Filigree.
5
+
6
+ module Filigree
7
+ VERSION = '0.1.2'
8
+ end
@@ -0,0 +1,195 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Filigree
3
+ # Date: 2014/02/11
4
+ # Description: An implementation of the Visitor pattern.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Standard Library
11
+
12
+ # Filigree
13
+ require 'filigree/class_methods_module'
14
+ require 'filigree/match'
15
+
16
+ #######################
17
+ # Classes and Modules #
18
+ #######################
19
+
20
+ module Filigree
21
+ # An implementation of the Visitor pattern.
22
+ module Visitor
23
+
24
+ include ClassMethodsModule
25
+
26
+ ####################
27
+ # Instance Methods #
28
+ ####################
29
+
30
+ # Find the correct pattern and execute its block on the provided
31
+ # objects.
32
+ #
33
+ # @param [Object] objects Objects to pattern match.
34
+ #
35
+ # @return [Object] Result of calling the matched pattern's block
36
+ #
37
+ # @raise [MatchError] Raised when no matching pattern is found
38
+ def call(*objects)
39
+ self.class.patterns.each do |pattern|
40
+ @match_bindings = OpenStruct.new
41
+
42
+ return pattern.(self, objects) if pattern.match?(objects, self)
43
+ end
44
+
45
+ # If we didn't find anything we raise a MatchError.
46
+ raise MatchError
47
+ end
48
+ alias :visit :call
49
+
50
+ #############
51
+ # Callbacks #
52
+ #############
53
+
54
+ # This is used to get and set binding names
55
+ def method_missing(name, *args)
56
+ if args.empty? and @match_bindings.respond_to?(name)
57
+ @match_bindings.send(name)
58
+ elsif name.to_s[-1] == '=' and args.length == 1
59
+ @match_bindings.send(name, *args)
60
+ else
61
+ super(name, *args)
62
+ end
63
+ end
64
+
65
+ #################
66
+ # Class Methods #
67
+ #################
68
+
69
+ module ClassMethods
70
+
71
+ attr_reader :patterns
72
+
73
+ # Force a name binding.
74
+ #
75
+ # @param [Symbol] name Name to bind to
76
+ #
77
+ # @return [BindingPattern]
78
+ def Bind(name)
79
+ BindingPattern.new(name)
80
+ end
81
+
82
+ # Force a literal comparison.
83
+ #
84
+ # @param [Object] obj Object to be comapred against
85
+ #
86
+ # @return [LiteralPattern]
87
+ def Literal(obj)
88
+ LiteralPattern.new(obj)
89
+ end
90
+
91
+ # Install the instance class variables in the including class.
92
+ #
93
+ # @return [void]
94
+ def install_icvars
95
+ @patterns = Array.new
96
+ @deferred = Array.new
97
+ end
98
+
99
+ # Define a pattern for this visitor.
100
+ #
101
+ # @see match Pattern matching description
102
+ #
103
+ # @param [Object] pattern List of pattern elements
104
+ # @param [Proc] block Block to be executed when the pattern is matched
105
+ #
106
+ # @return [void]
107
+ def on(*pattern, &block)
108
+ guard = if pattern.last.is_a?(Proc) then pattern.pop end
109
+
110
+ @patterns << (mp = OuterPattern.new(pattern, guard, block))
111
+
112
+ if block
113
+ @deferred.each { |pattern| pattern.block = block }
114
+ @deferred.clear
115
+
116
+ else
117
+ @deferred << mp
118
+ end
119
+ end
120
+
121
+ #############
122
+ # Callbacks #
123
+ #############
124
+
125
+ # Used to generate wildcard and binding patterns.
126
+ def method_missing(name, *args)
127
+ if args.empty?
128
+ if name == :_ then WildcardPattern.instance else BindingPattern.new(name) end
129
+ else
130
+ super(name, *args)
131
+ end
132
+ end
133
+
134
+ def self.extended(klass)
135
+ klass.install_icvars
136
+ end
137
+ end
138
+ end
139
+
140
+ # This class can be used to call multiple visitors on an object at once.
141
+ # This could potentialy reduce the number of times data structures are
142
+ # traversed.
143
+ class TourGuide
144
+ attr_reader :visitors
145
+
146
+ # Call each visitor on the specified objects.
147
+ #
148
+ # @param [Object] objects Objects to be visited
149
+ #
150
+ # @return [Array<Visitor>] The wrapped visitors
151
+ def call(*objects)
152
+ @visitors.each { |visitor| visitor.(*objects) }
153
+ end
154
+
155
+ # Construct a tour guide for a list of visitors.
156
+ #
157
+ # @param [Visitor] visitors List of visitors
158
+ def initialize(*visitors)
159
+ @visitors = visitors
160
+ end
161
+ end
162
+
163
+ # This module provides a default implementation of three common traversal
164
+ # patterns: pre-order, post-order, and in-order (level-order). The
165
+ # including class must implement the `children` function.
166
+ module Visitable
167
+
168
+ # Visit this object with the provided visitor in pre-, post-, or
169
+ # in-order traversal.
170
+ #
171
+ # @param [Visitor] visitor Visitor to call
172
+ # @param [:preorder, :inorder, :postorder] method How to visit
173
+ #
174
+ # @return [void]
175
+ def visit(visitor, method = :preorder)
176
+ case method
177
+ when :preorder
178
+ visitor.(self)
179
+ children.compact.each { |child| child.visit(visitor, :preorder) }
180
+
181
+ when :inorder
182
+ nodes = [self]
183
+
184
+ while node = nodes.shift
185
+ nodes += node.children.compact
186
+ visitor.(node)
187
+ end
188
+
189
+ when :postorder
190
+ children.compact.each { |child| child.visit(visitor, :postorder) }
191
+ visitor.(self)
192
+ end
193
+ end
194
+ end
195
+ end
data/lib/filigree.rb ADDED
@@ -0,0 +1,27 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Filigree
3
+ # Date: 2013/4/19
4
+ # Description: The root file for the Filigree project.
5
+
6
+ #############
7
+ # Requires #
8
+ ############
9
+
10
+ # Standard Library
11
+
12
+ # Filigree
13
+ require 'filigree/abstract_class'
14
+ require 'filigree/application'
15
+ require 'filigree/array'
16
+ require 'filigree/boolean'
17
+ require 'filigree/class'
18
+ require 'filigree/class_methods_module'
19
+ require 'filigree/commands'
20
+ require 'filigree/configuration'
21
+ require 'filigree/match'
22
+ require 'filigree/object'
23
+ require 'filigree/request_file'
24
+ require 'filigree/string'
25
+ require 'filigree/types'
26
+ require 'filigree/version'
27
+ require 'filigree/visitor'
@@ -0,0 +1,74 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Filigree
3
+ # Date: 2013/04/19
4
+ # Description: Test cases for the AbstractClass module.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Gems
11
+ require 'minitest/autorun'
12
+
13
+ # Filigree
14
+ require 'filigree/abstract_class'
15
+
16
+ #######################
17
+ # Classes and Modules #
18
+ #######################
19
+
20
+ class AbstractClassTester < Minitest::Test
21
+ class Foo
22
+ extend Filigree::AbstractClass
23
+
24
+ abstract_method :foo
25
+ end
26
+
27
+ class Bar < Foo; end
28
+
29
+ class Bam < Foo
30
+ def foo
31
+ true
32
+ end
33
+ end
34
+
35
+ class Baf < Foo
36
+ extend Filigree::AbstractClass
37
+ end
38
+
39
+ class Zap < Baf; end
40
+
41
+ def setup
42
+ end
43
+
44
+ def test_abstract_method
45
+ assert_raises(AbstractMethodError) { Bar.new.foo }
46
+
47
+ Bam.new.foo
48
+ end
49
+
50
+ def test_instantiate_abstract_class
51
+ assert_raises(AbstractClassError) { Foo.new }
52
+ end
53
+
54
+ def test_instantiate_subclass
55
+ Bar.new
56
+ end
57
+
58
+ def test_multi_level_abstract_hierarchy
59
+ assert_raises(AbstractClassError) { Baf.new }
60
+
61
+ Zap.new
62
+ end
63
+
64
+ def test_multiple_hierarchies
65
+ baf = Class.new { extend Filigree::AbstractClass }
66
+ baz = Class.new(baf)
67
+
68
+ assert_raises(AbstractClassError) { Foo.new }
69
+ assert_raises(AbstractClassError) { baf.new }
70
+
71
+ Bar.new
72
+ baz.new
73
+ end
74
+ end
@@ -0,0 +1,53 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Filigree
3
+ # Date: 2013/05/15
4
+ # Description: Test cases for the Application module.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Gems
11
+ require 'minitest/autorun'
12
+
13
+ # Filigree
14
+ require 'filigree/application'
15
+
16
+ #######################
17
+ # Classes and Modules #
18
+ #######################
19
+
20
+ class ApplicationTester < Minitest::Test
21
+ class Foo
22
+ include Filigree::Application
23
+ end
24
+
25
+ class Bar
26
+ include Filigree::Application
27
+
28
+ class Configuration
29
+ auto :foo do
30
+ :foo
31
+ end
32
+ end
33
+
34
+ def kill; end
35
+ def pause; end
36
+ def resume; end
37
+ def run; end
38
+ def stop; end
39
+ end
40
+
41
+ def setup
42
+
43
+ end
44
+
45
+ def test_application
46
+ assert_raises(NoMethodError) { Foo.finalize }
47
+ Bar.finalize
48
+ end
49
+
50
+ def test_embedded_config
51
+ assert_equal :foo, Bar.new.config.foo
52
+ end
53
+ end
data/test/tc_array.rb ADDED
@@ -0,0 +1,28 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Filigree
3
+ # Date: 2014/02/05
4
+ # Description: Test cases for the Array extensions.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Gems
11
+ require 'minitest/autorun'
12
+
13
+ # Filigree
14
+ require 'filigree/array'
15
+
16
+ #######################
17
+ # Classes and Modules #
18
+ #######################
19
+
20
+ class ArrayTester < Minitest::Test
21
+
22
+ def setup
23
+ end
24
+
25
+ def test_map_with_method
26
+ assert_equal [:cat, :dog, :cow], ['cat', 'dog', 'cow'].map(:to_sym)
27
+ end
28
+ end
@@ -0,0 +1,38 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Filigree
3
+ # Date: 2013/05/04
4
+ # Description: Test cases for Boolean extensions.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Gems
11
+ require 'minitest/autorun'
12
+
13
+ # Filigree
14
+ require 'filigree/boolean'
15
+
16
+ #######################
17
+ # Classes and Modules #
18
+ #######################
19
+
20
+ class BooleanTester < Minitest::Test
21
+ def setup
22
+
23
+ end
24
+
25
+ def test_integer
26
+ assert 1.to_bool
27
+ assert 10.to_bool
28
+ assert !0.to_bool
29
+ end
30
+
31
+ def test_true
32
+ assert_equal 1, true.to_i
33
+ end
34
+
35
+ def test_false
36
+ assert_equal 0, false.to_i
37
+ end
38
+ end
data/test/tc_class.rb ADDED
@@ -0,0 +1,45 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Filigree
3
+ # Date: 2013/05/04
4
+ # Description: Test cases for Class extensions.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Gems
11
+ require 'minitest/autorun'
12
+
13
+ # Filigree
14
+ require 'filigree/class'
15
+
16
+ #######################
17
+ # Classes and Modules #
18
+ #######################
19
+
20
+ class ClassTester < Minitest::Test
21
+ module Foo; end
22
+
23
+ class Bar
24
+ include Foo
25
+
26
+ class Baf; end
27
+ end
28
+
29
+ class Baz < Bar; end
30
+
31
+ def setup
32
+
33
+ end
34
+
35
+ def test_class
36
+ assert Bar.includes_module?(Foo)
37
+
38
+ assert_equal 'ClassTester::Bar::Baf', Bar::Baf.name
39
+ assert_equal 'Baf', Bar::Baf.short_name
40
+
41
+ assert Baz.subclass_of?(Bar)
42
+ assert !Baz.subclass_of?(Fixnum)
43
+ assert_raises(TypeError) { Baz.subclass_of?(1) }
44
+ end
45
+ end
@@ -0,0 +1,71 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Filigree
3
+ # Date: 2013/05/15
4
+ # Description: Test cases the InnerClassModule module.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Gems
11
+ require 'minitest/autorun'
12
+
13
+ # Filigree
14
+ require 'filigree/class_methods_module'
15
+
16
+ #######################
17
+ # Classes and Modules #
18
+ #######################
19
+
20
+ class ClassMethodsModuleTester < Minitest::Test
21
+ module Foo
22
+ include Filigree::ClassMethodsModule
23
+
24
+ def foo
25
+ :foo
26
+ end
27
+
28
+ module ClassMethods
29
+ def foo
30
+ :foo
31
+ end
32
+ end
33
+ end
34
+
35
+ module Baz
36
+ include Filigree::ClassMethodsModule
37
+
38
+ def baz
39
+ :baz
40
+ end
41
+
42
+ module ClassMethods
43
+ def baz
44
+ :baz
45
+ end
46
+ end
47
+ end
48
+
49
+ class Bar
50
+ include Foo
51
+ end
52
+
53
+ class Baf
54
+ include Foo
55
+ include Baz
56
+ end
57
+
58
+ def test_class_methods_module
59
+ assert_equal :foo, Bar.foo
60
+ assert_equal :foo, Bar.new.foo
61
+ end
62
+
63
+ def test_double_include
64
+
65
+ assert_equal :foo, Baf.foo
66
+ assert_equal :foo, Baf.new.foo
67
+
68
+ assert_equal :baz, Baf.baz
69
+ assert_equal :baz, Baf.new.baz
70
+ end
71
+ end