risitor 1.0.1

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.
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: []