Module: Funicular::Schema::RegexpTranslator

Defined in:
lib/funicular/schema.rb

Overview

Best-effort translation of a Ruby Regexp into a JS-RegExp-compatible source. The client runs Regexp as a JS RegExp wrapper, so Ruby-only constructs are either translated (A, z, Z anchors) or, when they have no safe JS equivalent, the validator is skipped with a warning.

Constant Summary collapse

INCOMPATIBLE =

Substrings that JS RegExp cannot accept; presence means “skip”.

['[[:', '\\h', '\\H', '\\G', '(?>'].freeze

Class Method Summary collapse

Class Method Details

.skip(reason) ⇒ Object



160
161
162
163
164
# File 'lib/funicular/schema.rb', line 160

def self.skip(reason)
  warn "[Funicular::Schema] skipping a format validator: #{reason}; " \
       "declare it directly in the Funicular::Model if needed"
  nil
end

.translate(regexp) ⇒ Object



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/funicular/schema.rb', line 139

def self.translate(regexp)
  return nil unless regexp.is_a?(Regexp)

  if (regexp.options & Regexp::EXTENDED) != 0
    return skip("extended (x) mode")
  end

  source = regexp.source
  if INCOMPATIBLE.any? { |token| source.include?(token) }
    return skip("uses a construct unsupported by JS RegExp")
  end

  js_source = source.gsub('\\A', '^').gsub('\\z', '$').gsub('\\Z', '$')

  flags = +''
  flags << 'i' if (regexp.options & Regexp::IGNORECASE) != 0
  flags << 'm' if (regexp.options & Regexp::MULTILINE) != 0

  { 'with' => js_source, 'flags' => flags }
end