epuber 0.7.4 → 0.8.0

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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -2
  3. data/README.md +2 -1
  4. data/epuber.gemspec +10 -12
  5. data/lib/epuber/book/contributor.rb +0 -1
  6. data/lib/epuber/book/file_request.rb +1 -1
  7. data/lib/epuber/book/target.rb +20 -23
  8. data/lib/epuber/book/toc_item.rb +2 -4
  9. data/lib/epuber/book.rb +19 -19
  10. data/lib/epuber/checker/bookspec_checker.rb +26 -0
  11. data/lib/epuber/checker/text_checker.rb +2 -1
  12. data/lib/epuber/checker.rb +16 -2
  13. data/lib/epuber/checker_transformer_base.rb +2 -5
  14. data/lib/epuber/command/build.rb +34 -24
  15. data/lib/epuber/command/init.rb +23 -23
  16. data/lib/epuber/command/server.rb +2 -2
  17. data/lib/epuber/command.rb +17 -20
  18. data/lib/epuber/compiler/compilation_context.rb +10 -8
  19. data/lib/epuber/compiler/file_database.rb +0 -2
  20. data/lib/epuber/compiler/file_finders/abstract.rb +33 -23
  21. data/lib/epuber/compiler/file_finders/imaginary.rb +40 -35
  22. data/lib/epuber/compiler/file_resolver.rb +77 -88
  23. data/lib/epuber/compiler/file_stat.rb +4 -4
  24. data/lib/epuber/compiler/file_types/abstract_file.rb +3 -4
  25. data/lib/epuber/compiler/file_types/bade_file.rb +12 -7
  26. data/lib/epuber/compiler/file_types/coffee_script_file.rb +1 -1
  27. data/lib/epuber/compiler/file_types/generated_file.rb +1 -1
  28. data/lib/epuber/compiler/file_types/image_file.rb +4 -2
  29. data/lib/epuber/compiler/file_types/nav_file.rb +0 -1
  30. data/lib/epuber/compiler/file_types/opf_file.rb +0 -1
  31. data/lib/epuber/compiler/file_types/source_file.rb +8 -3
  32. data/lib/epuber/compiler/file_types/xhtml_file.rb +67 -13
  33. data/lib/epuber/compiler/generator.rb +1 -2
  34. data/lib/epuber/compiler/meta_inf_generator.rb +1 -1
  35. data/lib/epuber/compiler/nav_generator.rb +5 -6
  36. data/lib/epuber/compiler/opf_generator.rb +22 -23
  37. data/lib/epuber/compiler/problem.rb +12 -21
  38. data/lib/epuber/compiler/xhtml_processor.rb +61 -31
  39. data/lib/epuber/compiler.rb +66 -19
  40. data/lib/epuber/config.rb +13 -7
  41. data/lib/epuber/dsl/attribute.rb +16 -17
  42. data/lib/epuber/dsl/attribute_support.rb +3 -3
  43. data/lib/epuber/dsl/object.rb +17 -15
  44. data/lib/epuber/dsl/tree_object.rb +2 -3
  45. data/lib/epuber/epubcheck.rb +15 -0
  46. data/lib/epuber/helper.rb +0 -1
  47. data/lib/epuber/lockfile.rb +7 -9
  48. data/lib/epuber/plugin.rb +1 -2
  49. data/lib/epuber/ruby_extensions/match_data.rb +1 -1
  50. data/lib/epuber/ruby_extensions/thread.rb +1 -0
  51. data/lib/epuber/server/base.styl +0 -1
  52. data/lib/epuber/server/basic.styl +1 -30
  53. data/lib/epuber/server/handlers.rb +1 -1
  54. data/lib/epuber/server.rb +67 -66
  55. data/lib/epuber/third_party/bower.rb +5 -5
  56. data/lib/epuber/transformer/text_transformer.rb +4 -2
  57. data/lib/epuber/transformer.rb +2 -2
  58. data/lib/epuber/user_interface.rb +49 -38
  59. data/lib/epuber/vendor/hash_binding.rb +9 -2
  60. data/lib/epuber/vendor/ruby_templater.rb +1 -5
  61. data/lib/epuber/vendor/version.rb +10 -10
  62. data/lib/epuber/version.rb +1 -1
  63. metadata +67 -69
  64. data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Bold.ttf +0 -0
  65. data/lib/epuber/server/fonts/AvenirNext/AvenirNext-BoldItalic.ttf +0 -0
  66. data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Italic.ttf +0 -0
  67. data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Regular.ttf +0 -0
@@ -50,9 +50,9 @@ module Epuber
50
50
  private
51
51
 
52
52
  def print_good_bye(book_id)
53
- puts <<-END.ansi.green
54
- Project initialized, please review #{book_id}.bookspec file, remove comments and fill some attributes like book title.
55
- END
53
+ UI.puts <<~TEXT.ansi.green
54
+ Project initialized, please review #{book_id}.bookspec file, remove comments and fill some attributes like book title.
55
+ TEXT
56
56
  end
57
57
 
58
58
  # Creates <book-id>.bookspec file from template
@@ -76,16 +76,18 @@ END
76
76
  # @return [void]
77
77
  #
78
78
  def write_sublime_project(book_id)
79
- text = '{
80
- "folders": [
81
- {
82
- "follow_symlinks": true,
83
- "path": ".",
84
- "folder_exclude_patterns": [".epuber"],
85
- "file_exclude_patterns": ["*.epub"]
86
- }
87
- ]
88
- }'
79
+ text = <<~JSON
80
+ {
81
+ "folders": [
82
+ {
83
+ "follow_symlinks": true,
84
+ "path": ".",
85
+ "folder_exclude_patterns": [".epuber"],
86
+ "file_exclude_patterns": ["*.epub"]
87
+ }
88
+ ]
89
+ }
90
+ JSON
89
91
 
90
92
  write("#{book_id}.sublime-project", text)
91
93
  end
@@ -95,7 +97,7 @@ END
95
97
  # @return [void]
96
98
  #
97
99
  def write_gitignore
98
- append_new_lines('.gitignore', <<~END
100
+ append_new_lines('.gitignore', <<~TEXT)
99
101
  # This is generated with `epuber init`
100
102
  *.epub
101
103
  *.mobi
@@ -104,15 +106,13 @@ END
104
106
  .epuber/release_build/
105
107
  .epuber/build_cache/
106
108
  .epuber/metadata/
107
- END
108
- )
109
+ TEXT
109
110
  end
110
111
 
111
112
  def write_default_style(book_id)
112
- write("styles/#{book_id}.styl", <<~END
113
+ write("styles/#{book_id}.styl", <<~STYLUS)
113
114
  // This is generated with `epuber init` script.
114
- END
115
- )
115
+ STYLUS
116
116
  end
117
117
 
118
118
  # @param string [String] text to file
@@ -122,7 +122,7 @@ END
122
122
  #
123
123
  def write(file_path, string)
124
124
  File.write(file_path, string)
125
- puts " #{'create'.ansi.green} #{file_path}"
125
+ UI.puts " #{'create'.ansi.green} #{file_path}"
126
126
  end
127
127
 
128
128
  # @param string [String] text to file
@@ -146,7 +146,7 @@ END
146
146
  existing_content << "\n"
147
147
 
148
148
  File.write(file_path, existing_content)
149
- puts " #{'update'.ansi.green} #{file_path}"
149
+ UI.puts " #{'update'.ansi.green} #{file_path}"
150
150
  end
151
151
 
152
152
  # @param [String] dir_path path to dir
@@ -155,7 +155,7 @@ END
155
155
  #
156
156
  def create_folder(dir_path)
157
157
  FileUtils.mkdir_p(dir_path)
158
- puts " #{'create'.ansi.green} #{dir_path}/"
158
+ UI.puts " #{'create'.ansi.green} #{dir_path}/"
159
159
  end
160
160
 
161
161
  # @param text [String]
@@ -167,7 +167,7 @@ END
167
167
  result = $stdin.gets.chomp
168
168
 
169
169
  while result.empty?
170
- puts 'Value cannot be empty, please fill it!'.ansi.red
170
+ UI.puts 'Value cannot be empty, please fill it!'.ansi.red
171
171
  print text
172
172
  result = $stdin.gets.chomp
173
173
  end
@@ -13,7 +13,7 @@ module Epuber
13
13
 
14
14
  def self.options
15
15
  [
16
- ['--open', 'Opens the web page in default web browser, working only on OS X'],
16
+ ['--open', 'Opens the web page in default web browser, working only on OS X'],
17
17
  ].concat(super)
18
18
  end
19
19
 
@@ -51,7 +51,7 @@ module Epuber
51
51
  if @open_web_browser
52
52
  system "open #{uri}"
53
53
  else
54
- puts 'Web browser can be automatically opened by adding --open flag, see --help'
54
+ UI.puts 'Web browser can be automatically opened by adding --open flag, see --help'
55
55
  end
56
56
  end
57
57
  end
@@ -21,21 +21,18 @@ module Epuber
21
21
  self.command = 'epuber'
22
22
  self.version = VERSION
23
23
  self.description = 'Epuber, easy creating and maintaining e-book.'
24
- self.plugin_prefixes = plugin_prefixes + %w(epuber)
24
+ self.plugin_prefixes = plugin_prefixes + %w[epuber]
25
25
 
26
26
  def self.run(argv = [])
27
- begin
28
- UI.current_command = self
29
- super
30
- UI.current_command = nil
31
-
32
- rescue Interrupt
33
- UI.error('[!] Cancelled')
34
- rescue => e
35
- UI.error!(e)
36
-
37
- UI.current_command = nil
38
- end
27
+ UI.current_command = self
28
+ super
29
+ UI.current_command = nil
30
+ rescue Interrupt
31
+ UI.error('[!] Cancelled')
32
+ rescue StandardError => e
33
+ UI.error!(e)
34
+
35
+ UI.current_command = nil
39
36
  end
40
37
 
41
38
  def validate!
@@ -70,18 +67,18 @@ module Epuber
70
67
  end
71
68
 
72
69
  def write_lockfile
73
- unless Epuber::Config.test?
74
- Epuber::Config.instance.save_lockfile
75
- end
70
+ return if Epuber::Config.test?
71
+
72
+ Epuber::Config.instance.save_lockfile
76
73
  end
77
74
 
78
75
  def pre_build_checks
79
76
  Config.instance.warn_for_outdated_versions!
80
77
 
81
- if !Config.instance.same_version_as_last_run? && File.exist?(Config.instance.working_path)
82
- UI.warning('Using different version of Epuber or Bade, removing all build caches')
83
- Config.instance.remove_build_caches
84
- end
78
+ return unless !Config.instance.same_version_as_last_run? && File.exist?(Config.instance.working_path)
79
+
80
+ UI.warning('Using different version of Epuber or Bade, removing all build caches')
81
+ Config.instance.remove_build_caches
85
82
  end
86
83
  end
87
84
  end
@@ -32,15 +32,13 @@ module Epuber
32
32
  #
33
33
  def plugins
34
34
  @plugins ||= @target.plugins.map do |path|
35
- begin
36
- plugin = Plugin.new(path)
37
- plugin.files.each do |file|
38
- file_resolver.add_file(file)
39
- end
40
- plugin
41
- rescue LoadError
42
- UI.error "Can't find plugin at path #{path}"
35
+ plugin = Plugin.new(path)
36
+ plugin.files.each do |file|
37
+ file_resolver.add_file(file)
43
38
  end
39
+ plugin
40
+ rescue LoadError
41
+ UI.error "Can't find plugin at path #{path}"
44
42
  end.compact
45
43
  end
46
44
 
@@ -100,6 +98,10 @@ module Epuber
100
98
  use_cache
101
99
  end
102
100
 
101
+ def release_build?
102
+ release_build
103
+ end
104
+
103
105
  def initialize(book, target)
104
106
  @book = book
105
107
  @target = target
@@ -7,7 +7,6 @@ module Epuber
7
7
  require_relative 'file_stat'
8
8
 
9
9
  class FileDatabase
10
-
11
10
  # @return [Hash<String, Epuber::Compiler::FileStat>]
12
11
  #
13
12
  attr_accessor :all_files
@@ -130,7 +129,6 @@ module Epuber
130
129
  _cleanup_stat_dependency_list(file_paths, next_stat)
131
130
  end
132
131
  end
133
-
134
132
  end
135
133
  end
136
134
  end
@@ -16,6 +16,8 @@ module Epuber
16
16
  # @param [String] context_path
17
17
  #
18
18
  def initialize(pattern, context_path)
19
+ super()
20
+
19
21
  @pattern = pattern
20
22
  @context_path = context_path
21
23
  end
@@ -48,6 +50,8 @@ module Epuber
48
50
  # @param [Array<String>] files_paths list of founded files
49
51
  #
50
52
  def initialize(pattern, groups, context_path, files_paths)
53
+ super()
54
+
51
55
  @pattern = pattern
52
56
  @groups = Array(groups)
53
57
  @context_path = context_path
@@ -61,16 +65,16 @@ module Epuber
61
65
  end
62
66
  end
63
67
 
64
- BINARY_EXTENSIONS = %w(.png .jpeg .jpg .otf .ttf)
65
- STATIC_EXTENSIONS = BINARY_EXTENSIONS + %w(.css .js)
68
+ BINARY_EXTENSIONS = %w[.png .jpeg .jpg .otf .ttf].freeze
69
+ STATIC_EXTENSIONS = BINARY_EXTENSIONS + %w[.css .js]
66
70
 
67
71
  GROUP_EXTENSIONS = {
68
- text: %w(.xhtml .html .bade),
69
- image: %w(.png .jpg .jpeg),
70
- font: %w(.otf .ttf),
71
- style: %w(.css .styl),
72
- script: %w(.js .coffee),
73
- }
72
+ text: %w[.xhtml .html .bade],
73
+ image: %w[.png .jpg .jpeg],
74
+ font: %w[.otf .ttf],
75
+ style: %w[.css .styl],
76
+ script: %w[.js .coffee],
77
+ }.freeze
74
78
 
75
79
  EXTENSIONS_RENAME = {
76
80
  '.styl' => '.css',
@@ -78,10 +82,9 @@ module Epuber
78
82
  '.bade' => '.xhtml',
79
83
 
80
84
  '.coffee' => '.js',
81
- }
85
+ }.freeze
82
86
 
83
87
  class Abstract
84
-
85
88
  # @return [String] path where should look for source files
86
89
  #
87
90
  attr_reader :source_path
@@ -99,7 +102,6 @@ module Epuber
99
102
  @ignored_patterns = []
100
103
  end
101
104
 
102
-
103
105
  # @param [Array<Symbol> | Symbol] groups
104
106
  #
105
107
  def assert_one_file(files, pattern: nil, groups: nil, context_path: nil)
@@ -113,7 +115,8 @@ module Epuber
113
115
  # When it founds too many (more than two) it will raise MultipleFilesFoundError
114
116
  #
115
117
  # @param [String] pattern pattern of the desired files
116
- # @param [Array<Symbol> | Symbol] groups list of group names, nil or empty array for all groups, for valid values see GROUP_EXTENSIONS
118
+ # @param [Array<Symbol> | Symbol] groups list of group names, nil or empty array for all groups, for valid
119
+ # values see GROUP_EXTENSIONS
117
120
  # @param [String] context_path path for root of searching, it is also defines start folder of relative path
118
121
  #
119
122
  # @return [Array<String>] list of founded files
@@ -128,7 +131,8 @@ module Epuber
128
131
  # #source_path and after that it tries to search recursively from #source_path.
129
132
  #
130
133
  # @param [String] pattern pattern of the desired files
131
- # @param [Array<Symbol>] groups list of group names, nil or empty array for all groups, for valid values see GROUP_EXTENSIONS
134
+ # @param [Array<Symbol>] groups list of group names, nil or empty array for all groups, for valid values see
135
+ # GROUP_EXTENSIONS
132
136
  # @param [String] context_path path for root of searching, it is also defines start folder of relative path
133
137
  #
134
138
  # @return [Array<String>] list of founded files
@@ -141,7 +145,9 @@ module Epuber
141
145
  searching_path = ::File.expand_path(context_path, @source_path_abs)
142
146
 
143
147
  unless searching_path.start_with?(@source_path_abs)
144
- raise "You can't search from folder (#{searching_path}) that is not sub folder of the source_path (#{source_path}) expanded to (#{@source_path_abs})."
148
+ raise <<~ERROR
149
+ You can't search from folder (#{searching_path}) that is not sub folder of the source_path (#{source_path}) expanded to (#{@source_path_abs}).
150
+ ERROR
145
151
  end
146
152
 
147
153
  files = __find_files(pattern, groups, searching_path)
@@ -152,7 +158,7 @@ module Epuber
152
158
  end
153
159
 
154
160
  if files.empty? && search_everywhere && !pattern.start_with?('**')
155
- files = __find_files('**/' + pattern, groups, @source_path_abs, searching_path || @source_path_abs)
161
+ files = __find_files("**/#{pattern}", groups, @source_path_abs, searching_path || @source_path_abs)
156
162
  end
157
163
 
158
164
  files
@@ -161,13 +167,14 @@ module Epuber
161
167
  # Looks for all files from #source_path recursively
162
168
  #
163
169
  # @param [String] pattern pattern of the desired files
164
- # @param [Array<Symbol>] groups list of group names, nil or empty array for all groups, for valid values see GROUP_EXTENSIONS
170
+ # @param [Array<Symbol>] groups list of group names, nil or empty array for all groups, for valid values see
171
+ # GROUP_EXTENSIONS
165
172
  # @param [String] context_path path for root of searching, it is also defines start folder of relative path
166
173
  #
167
174
  # @return [Array<String>] list of founded files
168
175
  #
169
176
  def find_all(pattern, groups: nil, context_path: @source_path_abs)
170
- __find_files('**/' + pattern, groups, context_path)
177
+ __find_files("**/#{pattern}", groups, context_path)
171
178
  end
172
179
 
173
180
  # @param [Array<String>] paths list of file paths
@@ -209,7 +216,8 @@ module Epuber
209
216
  # Looks for files at given context path, if there is no file, it will try again with pattern for any extension
210
217
  #
211
218
  # @param [String] pattern pattern of the desired files
212
- # @param [Array<Symbol>] groups list of group names, nil or empty array for all groups, for valid values see GROUP_EXTENSIONS
219
+ # @param [Array<Symbol>] groups list of group names, nil or empty array for all groups, for valid values see
220
+ # GROUP_EXTENSIONS
213
221
  # @param [String] context_path path for root of searching, it is also defines start folder of relative path
214
222
  # @param [String] orig_context_path original context path, wo it will work nicely with iterative searching
215
223
  #
@@ -222,15 +230,17 @@ module Epuber
222
230
  files = __core_find_files(pattern, groups, context_path, orig_context_path)
223
231
 
224
232
  # try to find files with any extension
225
- files = __core_find_files(pattern + '.*', groups, context_path, orig_context_path) if files.empty?
233
+ files = __core_find_files("#{pattern}.*", groups, context_path, orig_context_path) if files.empty?
226
234
 
227
235
  files
228
236
  end
229
237
 
230
- # Core method for finding files, it only search for files, filter by input groups and map the final paths to pretty relative paths from context_path
238
+ # Core method for finding files, it only search for files, filter by input groups and map the final paths to
239
+ # pretty relative paths from context_path
231
240
  #
232
241
  # @param [String] pattern pattern of the desired files
233
- # @param [Array<Symbol>] groups list of group names, nil or empty array for all groups, for valid values see GROUP_EXTENSIONS
242
+ # @param [Array<Symbol>] groups list of group names, nil or empty array for all groups, for valid values see
243
+ # GROUP_EXTENSIONS
234
244
  # @param [String] context_path path for root of searching, it is also defines start folder of relative path
235
245
  # @param [String] orig_context_path original context path, wo it will work nicely with iterative searching
236
246
  #
@@ -258,11 +268,11 @@ module Epuber
258
268
  self.class.relative_paths_from(file_paths, orig_context_path)
259
269
  end
260
270
 
261
- def __core_find_files_from_pattern(pattern)
271
+ def __core_find_files_from_pattern(_pattern)
262
272
  raise 'Implement this in subclass'
263
273
  end
264
274
 
265
- def __core_file?(path)
275
+ def __core_file?(_path)
266
276
  raise 'Implement this in subclass'
267
277
  end
268
278
  end
@@ -11,6 +11,8 @@ module Epuber
11
11
  #
12
12
  attr_accessor :entries
13
13
 
14
+ # @return [String]
15
+ #
14
16
  attr_reader :name
15
17
 
16
18
  def initialize(name)
@@ -32,8 +34,12 @@ module Epuber
32
34
  end
33
35
 
34
36
  class FileEntry
37
+ # @return [String]
38
+ #
35
39
  attr_reader :name
36
40
 
41
+ # @return [String]
42
+ #
37
43
  attr_reader :absolute_path
38
44
 
39
45
  def initialize(name, absolute_path)
@@ -42,7 +48,7 @@ module Epuber
42
48
  end
43
49
 
44
50
  def ==(other)
45
- other.is_a?(FileEntry) ? name == other.name : name == other.to_s
51
+ name == (other.is_a?(FileEntry) ? other.name : other.to_s)
46
52
  end
47
53
  end
48
54
 
@@ -83,14 +89,11 @@ module Epuber
83
89
  make_dir_p(path)[file_name] = FileEntry.new(file_name, file_path)
84
90
  end
85
91
 
86
-
87
92
  def __core_find_files_from_pattern(pattern)
88
93
  parts = self.class.path_parts(pattern)
89
94
  found_entries = find_recurser(root, parts).flatten
90
95
  file_entries = found_entries.reject { |entry| entry.is_a?(DirEntry) }
91
- file_entries.map do |item|
92
- item.absolute_path
93
- end
96
+ file_entries.map(&:absolute_path)
94
97
  end
95
98
 
96
99
  def __core_file?(path)
@@ -104,12 +107,14 @@ module Epuber
104
107
  current.is_a?(FileEntry)
105
108
  end
106
109
 
107
- private
108
-
109
- def self.path_parts(path)
110
- path.split(File::SEPARATOR).reject(&:empty?)
110
+ class << self
111
+ def path_parts(path)
112
+ path.split(File::SEPARATOR).reject(&:empty?)
113
+ end
111
114
  end
112
115
 
116
+ private
117
+
113
118
  def find_recurser(dir, parts)
114
119
  return [] unless dir.respond_to? :[]
115
120
 
@@ -117,25 +122,25 @@ module Epuber
117
122
  return [] if pattern.nil?
118
123
 
119
124
  matches = case pattern
120
- when '**'
121
- case parts
122
- when ['*']
123
- parts = [] # end recursion
124
- directories_under(dir).map do |d|
125
- d.entries.select do |f|
126
- (f.is_a?(FileEntry) || f.is_a?(DirEntry)) &&
127
- f.name.match(/\A(?!\.)/)
128
- end
129
- end.flatten.uniq
130
- when []
131
- parts = [] # end recursion
132
- dir.entries.values.flatten.uniq
133
- else
134
- directories_under(dir)
135
- end
125
+ when '**'
126
+ case parts
127
+ when ['*']
128
+ parts = [] # end recursion
129
+ directories_under(dir).map do |d|
130
+ d.entries.select do |f|
131
+ (f.is_a?(FileEntry) || f.is_a?(DirEntry)) &&
132
+ f.name.match(/\A(?!\.)/)
133
+ end
134
+ end.flatten.uniq
135
+ when []
136
+ parts = [] # end recursion
137
+ dir.entries.values.flatten.uniq
136
138
  else
137
- regex_body = pattern_to_regex(pattern)
138
- dir.entries.reject { |k, _v| /\A#{regex_body}\Z/ !~ k }.values
139
+ directories_under(dir)
140
+ end
141
+ else
142
+ regex_body = pattern_to_regex(pattern)
143
+ dir.entries.select { |k, _v| /\A#{regex_body}\Z/ =~ k }.values
139
144
  end
140
145
 
141
146
  if parts.empty? # we're done recursing
@@ -156,14 +161,14 @@ module Epuber
156
161
 
157
162
  def pattern_to_regex(pattern)
158
163
  pattern.gsub('.', '\.')
159
- .gsub('?', '.')
160
- .gsub('*', '.*')
161
- .gsub('(', '\(')
162
- .gsub(')', '\)')
163
- .gsub(/\{(.*?)\}/) do
164
- "(#{Regexp.last_match[1].gsub(',', '|')})"
165
- end
166
- .gsub(/\A\./, '(?!\.).')
164
+ .gsub('?', '.')
165
+ .gsub('*', '.*')
166
+ .gsub('(', '\(')
167
+ .gsub(')', '\)')
168
+ .gsub(/\{(.*?)\}/) do
169
+ "(#{Regexp.last_match[1].gsub(',', '|')})"
170
+ end
171
+ .gsub(/\A\./, '(?!\.).')
167
172
  end
168
173
  end
169
174
  end