risitor 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f83e529945dc5da5ac952f4e85b6eb454f4b0e2c
4
+ data.tar.gz: e2cba098ab838db018aeef47091e8d16bd5bb2e5
5
+ SHA512:
6
+ metadata.gz: 48653f25fe5a6c89dd95c86ee16198be29c69edfa0a5b160ad3b10833f97517ba7f86ab0e1abb287f2807f02c622ad4ca3afe6aa1ef3ef966e42c336101950f0
7
+ data.tar.gz: 97a61929cba44373c0ee32e6c7acd490ad5fc9c19e3343c44524d1e079494d2ee4c9c74640fd4e38763c24e68303c0a23d8ad69528833288a6906a68239652e4
@@ -0,0 +1,16 @@
1
+ module Risitor
2
+ # Error raised when a Visitor failed to visit an object.
3
+ class NoVisitMethodError < NoMethodError
4
+ attr_reader :visitor, :visited, :visited_as
5
+
6
+ def initialize(visitor, visited, visited_as)
7
+ @visitor = visitor
8
+ @visited = visited
9
+ @visited_as = visited_as
10
+ end
11
+
12
+ def message
13
+ "no method in #{@visitor} to visit as #{@visited_as}"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,24 @@
1
+ module Risitor
2
+ # Helper for visit methods generation, matching & co.
3
+ module VisitMethodHelper
4
+ TEMPLATE = "visit[%s]"
5
+ REGEXP = /^visit\[(.*)\]$/
6
+
7
+ # Return a visit method name for the type +type+.
8
+ def self.gen_name(type)
9
+ return TEMPLATE % type.name
10
+ end
11
+
12
+ # Return true if the +visit_method_name+ is a well formed
13
+ # visit method name, else false.
14
+ def self.match(visit_method_name)
15
+ return REGEXP.match visit_method_name
16
+ end
17
+
18
+ # Return the type matching a visit method.
19
+ def self.get_type(visit_method)
20
+ type_symbol = match(visit_method).captures[0]
21
+ return const_get type_symbol
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,121 @@
1
+ require_relative './no_visit_method_error'
2
+ require_relative './visit_method_helper'
3
+
4
+ module Risitor
5
+ # The Visitor module can extend a module or include a class
6
+ # to make it a dynamic visitor (see the OOP visitor pattern).
7
+ module Visitor
8
+ # Calling visit execute the method associated with the
9
+ # type of +object+.
10
+ def visit(object, *args, as: object.class)
11
+ as.ancestors.each do |type|
12
+ visit_method = VisitMethodHelper.gen_name(type)
13
+ next unless respond_to? visit_method
14
+ return send(visit_method, object, *args)
15
+ end
16
+ raise NoVisitMethodError.new(self, object, as)
17
+ end
18
+
19
+ # List of the methods extended by a Visitor
20
+ module ClassMethods
21
+ # Alias the `visit` method
22
+ def alias_visit_method(visit_method_alias)
23
+ define_new_visit_method(visit_method_alias)
24
+ end
25
+
26
+ # Add/override a visit method for the types +types+.
27
+ def add_visit_method(*types, &block)
28
+ block = block.curry(1) if block.arity == 0
29
+ types.each do |type|
30
+ define_visit_method_for type, &block
31
+ end
32
+ end
33
+
34
+ # Remove the visit methods for the types +types+.
35
+ def remove_visit_method(*types)
36
+ types.each do |type|
37
+ undefine_visit_method_for type
38
+ end
39
+ end
40
+
41
+ # Remove all the visit methods.
42
+ def reset_visit_methods
43
+ visit_methods.each do |visit_method|
44
+ undefine_visit_method visit_method
45
+ end
46
+ end
47
+
48
+ # Return a list of the visit method.
49
+ def visit_methods
50
+ return methods.select do |method|
51
+ VisitMethodHelper.match method
52
+ end
53
+ end
54
+
55
+ # Return a list of the types with a visit method.
56
+ def visitable_types
57
+ return visit_methods.collect do |visit_method|
58
+ VisitMethodHelper.get_type(visit_method)
59
+ end
60
+ end
61
+
62
+ alias_method :when_visiting, :add_visit_method
63
+ end
64
+
65
+ # List of the methods extended by a Visitor when included.
66
+ module ClassMethodsWhenIncluded
67
+ private
68
+
69
+ def define_new_visit_method(new_visit_method)
70
+ define_method new_visit_method, instance_method(:visit)
71
+ end
72
+
73
+ def define_visit_method_for(klass, &block)
74
+ define_method VisitMethodHelper.gen_name(klass), block
75
+ end
76
+
77
+ def undefine_visit_method_for(klass)
78
+ remove_method VisitMethodHelper.gen_name(klass)
79
+ end
80
+
81
+ def undefine_visit_method(visit_method)
82
+ remove_method visit_method
83
+ end
84
+ end
85
+
86
+ # List of the methods extended by a Visitor when included.
87
+ module ClassMethodsWhenExtended
88
+ private
89
+
90
+ def define_new_visit_method(new_visit_method)
91
+ define_singleton_method new_visit_method, method(:visit)
92
+ end
93
+
94
+ def define_visit_method_for(klass, &block)
95
+ define_singleton_method VisitMethodHelper.gen_name(klass), block
96
+ end
97
+
98
+ def undefine_visit_method_for(klass)
99
+ self.singleton_class.send :remove_method, VisitMethodHelper.gen_name(klass)
100
+ end
101
+
102
+ def undefine_visit_method(visit_method)
103
+ self.singleton_class.send :remove_method, visit_method
104
+ end
105
+ end
106
+
107
+ class << self
108
+ def included(visitor)
109
+ visitor.extend ClassMethods
110
+ visitor.extend ClassMethodsWhenIncluded
111
+ end
112
+
113
+ def extended(visitor)
114
+ visitor.extend ClassMethods
115
+ visitor.extend ClassMethodsWhenExtended
116
+ end
117
+ end
118
+ end
119
+
120
+ Base = Visitor
121
+ end
data/lib/risitor.rb ADDED
@@ -0,0 +1,5 @@
1
+ # Risitor is a Ruby visitor pattern helper.
2
+ module Risitor
3
+ end
4
+
5
+ require_relative './risitor/visitor'
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: risitor
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Pierre Le Gall
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-09-08 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Make the visitor pattern accessible and flexible inside Ruby.
14
+ email: pierre@legall.im
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/risitor.rb
20
+ - lib/risitor/no_visit_method_error.rb
21
+ - lib/risitor/visit_method_helper.rb
22
+ - lib/risitor/visitor.rb
23
+ homepage: http://github.com/lepieru/risitor
24
+ licenses:
25
+ - MIT
26
+ metadata: {}
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubyforge_project:
43
+ rubygems_version: 2.5.1
44
+ signing_key:
45
+ specification_version: 4
46
+ summary: A visitor pattern helper for Ruby.
47
+ test_files: []