/
verbal_expressions.rb
189 lines (153 loc) · 3.54 KB
/
verbal_expressions.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# Ruby Verbal Expressions, based on the awesome JavaScript repo by @jehna: https://github.com/jehna/VerbalExpressions
# For documentation and install instructions,
# see the main Ruby repo: https://github.com/ryan-endacott/VerbalExpressions.rb
class VerEx < Regexp
def initialize(&block)
@prefixes = ""
@source = ""
@suffixes = ""
@modifiers = "" # TODO: Ruby Regexp option flags
@self_before_instance_eval = eval "self", block.binding
instance_eval &block
super(@prefixes + @source + @suffixes, @modifiers)
end
def method_missing(method, *args, &block)
@self_before_instance_eval.send method, *args, &block
end
# We try to keep the syntax as
# user-friendly as possible.
# So we can use the "normal"
# behaviour to split the "sentences"
# naturally.
# TODO: then is reserved in ruby, so use find or think of a better name
def find(value)
value = sanitize(value)
add("(?:#{value})")
end
# start or end of line
def start_of_line(enable = true)
@prefixes = '^' if enable
end
def end_of_line(enable = true)
@suffixes = '$' if enable
end
# Maybe is used to add values with ?
def maybe(value)
value = sanitize(value)
add("(?:#{value})?")
end
# Any character any number of times
def anything
add("(?:.*)")
end
# Anything but these characters
def anything_but(value)
value = sanitize(value)
add("(?:[^#{value}]*)")
end
# Regular expression special chars
def line_break
add('(?:\n|(?:\r\n))')
end
# And a shorthand for html-minded
alias_method :br, :line_break
def tab
add('\t')
end
# Any single alphanumeric
def letter
add('\w')
end
# Any word (multiple alphanumerics)
def word
one_or_more { letter }
end
# Any single digit
def digit
add('\d')
end
# Any integer (multiple digits)
def integer
one_or_more { digit }
end
# Any whitespace character
def whitespace()
add('\s+')
end
# Any given character
def any_of(value)
value = sanitize(value)
add("[#{value}]")
end
#At least one of some other thing
def one_or_more(&b)
add("(?:")
yield
add(")+")
end
def zero_or_more(&b)
add("(?:")
yield
add(")*")
end
alias_method :any, :any_of
# Usage: range( from, to [, from, to ... ] )
def range(*args)
value = "["
args.each_slice(2) do |from, to|
from = sanitize(from)
to = sanitize(to)
value += "#{from}-#{to}"
end
value += "]"
add(value)
end
# Loops
def multiple(value)
value = sanitize(value)
value += "+"
add(value)
end
# Adds alternative expressions
# TODO: or is a reserved keyword in ruby, think of better name
def alternatively(value = nil)
@prefixes += "(?:" unless @prefixes.include?("(")
@suffixes = ")" + @suffixes unless @suffixes.include?(")")
add(")|(?:")
find(value) if value
end
# Capture groups (can optionally name)
def begin_capture(name = nil)
if name
add("(?<#{name}>")
else
add("(")
end
end
def end_capture
add(")")
end
def capture(name = nil, &block)
begin_capture(name)
yield
end_capture
end
private
# Sanitation function for adding
# anything safely to the expression
def sanitize(value)
case value
when Regexp, VerEx
value.source
else
Regexp.quote(value)
end
end
# Function to add stuff to the
# expression. Also compiles the
# new expression so it's ready to
# be used.
def add(value = '')
@source += value
end
end