mustermann 1.0.1 → 1.0.2.rc1

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 (126) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +18 -0
  3. data/.rspec +5 -0
  4. data/.travis.yml +25 -0
  5. data/.yardopts +3 -0
  6. data/Gemfile +7 -0
  7. data/README.md +230 -799
  8. data/Rakefile +27 -0
  9. data/mustermann-contrib/LICENSE +23 -0
  10. data/mustermann-contrib/README.md +1155 -0
  11. data/mustermann-contrib/examples/highlighting.rb +35 -0
  12. data/mustermann-contrib/highlighting.png +0 -0
  13. data/mustermann-contrib/irb.png +0 -0
  14. data/mustermann-contrib/lib/mustermann/cake.rb +19 -0
  15. data/mustermann-contrib/lib/mustermann/express.rb +38 -0
  16. data/mustermann-contrib/lib/mustermann/file_utils.rb +218 -0
  17. data/mustermann-contrib/lib/mustermann/file_utils/glob_pattern.rb +40 -0
  18. data/mustermann-contrib/lib/mustermann/fileutils.rb +1 -0
  19. data/mustermann-contrib/lib/mustermann/flask.rb +199 -0
  20. data/mustermann-contrib/lib/mustermann/pyramid.rb +29 -0
  21. data/mustermann-contrib/lib/mustermann/rails.rb +47 -0
  22. data/mustermann-contrib/lib/mustermann/shell.rb +57 -0
  23. data/mustermann-contrib/lib/mustermann/simple.rb +51 -0
  24. data/mustermann-contrib/lib/mustermann/string_scanner.rb +314 -0
  25. data/mustermann-contrib/lib/mustermann/strscan.rb +1 -0
  26. data/mustermann-contrib/lib/mustermann/template.rb +63 -0
  27. data/mustermann-contrib/lib/mustermann/uri_template.rb +1 -0
  28. data/mustermann-contrib/lib/mustermann/versions.rb +47 -0
  29. data/mustermann-contrib/lib/mustermann/visualizer.rb +39 -0
  30. data/mustermann-contrib/lib/mustermann/visualizer/highlight.rb +138 -0
  31. data/mustermann-contrib/lib/mustermann/visualizer/highlighter.rb +38 -0
  32. data/mustermann-contrib/lib/mustermann/visualizer/highlighter/ad_hoc.rb +95 -0
  33. data/mustermann-contrib/lib/mustermann/visualizer/highlighter/ast.rb +103 -0
  34. data/mustermann-contrib/lib/mustermann/visualizer/highlighter/composite.rb +46 -0
  35. data/mustermann-contrib/lib/mustermann/visualizer/highlighter/dummy.rb +19 -0
  36. data/mustermann-contrib/lib/mustermann/visualizer/highlighter/regular.rb +105 -0
  37. data/mustermann-contrib/lib/mustermann/visualizer/pattern_extension.rb +69 -0
  38. data/mustermann-contrib/lib/mustermann/visualizer/renderer/ansi.rb +24 -0
  39. data/mustermann-contrib/lib/mustermann/visualizer/renderer/generic.rb +47 -0
  40. data/mustermann-contrib/lib/mustermann/visualizer/renderer/hansi_template.rb +35 -0
  41. data/mustermann-contrib/lib/mustermann/visualizer/renderer/html.rb +51 -0
  42. data/mustermann-contrib/lib/mustermann/visualizer/renderer/sexp.rb +38 -0
  43. data/mustermann-contrib/lib/mustermann/visualizer/tree.rb +64 -0
  44. data/mustermann-contrib/lib/mustermann/visualizer/tree_renderer.rb +79 -0
  45. data/mustermann-contrib/mustermann-contrib.gemspec +19 -0
  46. data/mustermann-contrib/spec/cake_spec.rb +91 -0
  47. data/mustermann-contrib/spec/express_spec.rb +210 -0
  48. data/mustermann-contrib/spec/file_utils_spec.rb +120 -0
  49. data/mustermann-contrib/spec/flask_spec.rb +362 -0
  50. data/mustermann-contrib/spec/flask_subclass_spec.rb +369 -0
  51. data/mustermann-contrib/spec/pattern_extension_spec.rb +50 -0
  52. data/mustermann-contrib/spec/pyramid_spec.rb +102 -0
  53. data/mustermann-contrib/spec/rails_spec.rb +648 -0
  54. data/mustermann-contrib/spec/shell_spec.rb +148 -0
  55. data/mustermann-contrib/spec/simple_spec.rb +269 -0
  56. data/mustermann-contrib/spec/string_scanner_spec.rb +272 -0
  57. data/mustermann-contrib/spec/template_spec.rb +842 -0
  58. data/mustermann-contrib/spec/visualizer_spec.rb +199 -0
  59. data/mustermann-contrib/theme.png +0 -0
  60. data/mustermann-contrib/tree.png +0 -0
  61. data/mustermann/LICENSE +23 -0
  62. data/mustermann/README.md +853 -0
  63. data/{bench → mustermann/bench}/capturing.rb +0 -0
  64. data/{bench → mustermann/bench}/regexp.rb +0 -0
  65. data/{bench → mustermann/bench}/simple_vs_sinatra.rb +0 -0
  66. data/{bench → mustermann/bench}/template_vs_addressable.rb +0 -0
  67. data/{lib → mustermann/lib}/mustermann.rb +0 -0
  68. data/{lib → mustermann/lib}/mustermann/ast/boundaries.rb +0 -0
  69. data/{lib → mustermann/lib}/mustermann/ast/compiler.rb +0 -0
  70. data/{lib → mustermann/lib}/mustermann/ast/expander.rb +0 -0
  71. data/{lib → mustermann/lib}/mustermann/ast/node.rb +0 -0
  72. data/{lib → mustermann/lib}/mustermann/ast/param_scanner.rb +0 -0
  73. data/{lib → mustermann/lib}/mustermann/ast/parser.rb +0 -0
  74. data/{lib → mustermann/lib}/mustermann/ast/pattern.rb +0 -0
  75. data/{lib → mustermann/lib}/mustermann/ast/template_generator.rb +0 -0
  76. data/{lib → mustermann/lib}/mustermann/ast/transformer.rb +0 -0
  77. data/{lib → mustermann/lib}/mustermann/ast/translator.rb +0 -0
  78. data/{lib → mustermann/lib}/mustermann/ast/validation.rb +0 -0
  79. data/{lib → mustermann/lib}/mustermann/caster.rb +0 -0
  80. data/{lib → mustermann/lib}/mustermann/composite.rb +0 -0
  81. data/{lib → mustermann/lib}/mustermann/concat.rb +13 -2
  82. data/{lib → mustermann/lib}/mustermann/equality_map.rb +0 -0
  83. data/{lib → mustermann/lib}/mustermann/error.rb +0 -0
  84. data/{lib → mustermann/lib}/mustermann/expander.rb +0 -0
  85. data/{lib → mustermann/lib}/mustermann/extension.rb +0 -0
  86. data/{lib → mustermann/lib}/mustermann/identity.rb +0 -0
  87. data/{lib → mustermann/lib}/mustermann/mapper.rb +0 -0
  88. data/{lib → mustermann/lib}/mustermann/pattern.rb +1 -1
  89. data/{lib → mustermann/lib}/mustermann/pattern_cache.rb +0 -0
  90. data/{lib → mustermann/lib}/mustermann/regexp.rb +0 -0
  91. data/{lib → mustermann/lib}/mustermann/regexp_based.rb +0 -0
  92. data/{lib → mustermann/lib}/mustermann/regular.rb +0 -0
  93. data/{lib → mustermann/lib}/mustermann/simple_match.rb +0 -0
  94. data/{lib → mustermann/lib}/mustermann/sinatra.rb +1 -1
  95. data/{lib → mustermann/lib}/mustermann/sinatra/parser.rb +0 -0
  96. data/{lib → mustermann/lib}/mustermann/sinatra/safe_renderer.rb +0 -0
  97. data/{lib → mustermann/lib}/mustermann/sinatra/try_convert.rb +0 -0
  98. data/{lib → mustermann/lib}/mustermann/to_pattern.rb +0 -0
  99. data/{lib → mustermann/lib}/mustermann/version.rb +1 -1
  100. data/{mustermann.gemspec → mustermann/mustermann.gemspec} +0 -0
  101. data/{spec → mustermann/spec}/ast_spec.rb +0 -0
  102. data/{spec → mustermann/spec}/composite_spec.rb +0 -0
  103. data/{spec → mustermann/spec}/concat_spec.rb +12 -0
  104. data/{spec → mustermann/spec}/equality_map_spec.rb +0 -0
  105. data/{spec → mustermann/spec}/expander_spec.rb +0 -0
  106. data/{spec → mustermann/spec}/extension_spec.rb +0 -0
  107. data/{spec → mustermann/spec}/identity_spec.rb +0 -0
  108. data/{spec → mustermann/spec}/mapper_spec.rb +0 -0
  109. data/{spec → mustermann/spec}/mustermann_spec.rb +0 -0
  110. data/{spec → mustermann/spec}/pattern_spec.rb +0 -0
  111. data/{spec → mustermann/spec}/regexp_based_spec.rb +0 -0
  112. data/{spec → mustermann/spec}/regular_spec.rb +0 -0
  113. data/{spec → mustermann/spec}/simple_match_spec.rb +0 -0
  114. data/{spec → mustermann/spec}/sinatra_spec.rb +0 -0
  115. data/{spec → mustermann/spec}/to_pattern_spec.rb +0 -0
  116. data/support/lib/support.rb +7 -0
  117. data/support/lib/support/coverage.rb +23 -0
  118. data/support/lib/support/env.rb +19 -0
  119. data/support/lib/support/expand_matcher.rb +28 -0
  120. data/support/lib/support/generate_template_matcher.rb +27 -0
  121. data/support/lib/support/match_matcher.rb +39 -0
  122. data/support/lib/support/pattern.rb +42 -0
  123. data/support/lib/support/projects.rb +20 -0
  124. data/support/lib/support/scan_matcher.rb +63 -0
  125. data/support/support.gemspec +27 -0
  126. metadata +128 -58
File without changes
File without changes
File without changes
@@ -10,8 +10,19 @@ module Mustermann
10
10
  # @!visibility private
11
11
  def +(other)
12
12
  other &&= Mustermann.new(other, type: :identity, **options)
13
- return super unless native = native_concat(other)
14
- self.class.new(native, **options)
13
+ if (patterns = look_ahead(other)) && !patterns.empty?
14
+ concat = (self + patterns.inject(:+))
15
+ concat + other.patterns.slice(patterns.length..-1).inject(:+)
16
+ else
17
+ return super unless native = native_concat(other)
18
+ self.class.new(native, **options)
19
+ end
20
+ end
21
+
22
+ # @!visibility private
23
+ def look_ahead(other)
24
+ return unless other.is_a?(Concat)
25
+ other.patterns.take_while(&method(:native_concat?))
15
26
  end
16
27
 
17
28
  # @!visibility private
@@ -226,7 +226,7 @@ module Mustermann
226
226
  # warn "does not support expanding"
227
227
  # end
228
228
  #
229
- # Expanding is supported by almost all patterns (notable execptions are {Mustermann::Shell},
229
+ # Expanding is supported by almost all patterns (notable exceptions are {Mustermann::Shell},
230
230
  # {Mustermann::Regular} and {Mustermann::Simple}).
231
231
  #
232
232
  # Union {Mustermann::Composite} patterns (with the | operator) support expanding if all
@@ -42,7 +42,7 @@ module Mustermann
42
42
  # If a string is supplied, it is treated as a fully escaped Sinatra pattern.
43
43
  #
44
44
  # If the other pattern is also a Sintara pattern, it might join the two to a third
45
- # sinatra pattern instead of generating a composite for efficency reasons.
45
+ # sinatra pattern instead of generating a composite for efficiency reasons.
46
46
  #
47
47
  # This only happens if the sinatra pattern behaves exactly the same as a composite
48
48
  # would in regards to matching, parsing, expanding and template generation.
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Mustermann
3
- VERSION ||= '1.0.1'
3
+ VERSION ||= '1.0.2.rc1'
4
4
  end
File without changes
@@ -57,6 +57,18 @@ describe Mustermann::Concat do
57
57
  its(:class) { should be == Mustermann::Concat }
58
58
  its(:to_s) { should be == '(sinatra:"/:foo" + rails:"/:bar" + sinatra:"/:baz")' }
59
59
  end
60
+
61
+ context "sinatra + (sinatra + regular)" do
62
+ subject(:pattern) { Mustermann.new("/foo") + (Mustermann.new("/bar") + Mustermann.new(/baz/)) }
63
+ its(:class) { should be == Mustermann::Concat }
64
+ its(:to_s) { should be == '(sinatra:"/foo/bar" + regular:"baz")' }
65
+ end
66
+
67
+ context "sinatra + (sinatra + rails (different options) + sinatra)" do
68
+ subject(:pattern) { Mustermann.new("/foo") + (Mustermann.new("/bar") + Mustermann.new("/baz", type: :rails, uri_decode: false) + Mustermann.new("/boo")) }
69
+ its(:class) { should be == Mustermann::Concat }
70
+ its(:to_s) { should be == '(sinatra:"/foo/bar" + rails:"/baz" + sinatra:"/boo")' }
71
+ end
60
72
  end
61
73
 
62
74
  subject(:pattern) { Mustermann::Concat.new("/:foo", "/:bar") }
File without changes
@@ -0,0 +1,7 @@
1
+ require 'support/env'
2
+ require 'support/coverage'
3
+ require 'support/expand_matcher'
4
+ require 'support/generate_template_matcher'
5
+ require 'support/match_matcher'
6
+ require 'support/pattern'
7
+ require 'support/scan_matcher'
@@ -0,0 +1,23 @@
1
+ require 'simplecov'
2
+ require 'coveralls'
3
+ require 'support/projects'
4
+
5
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
6
+ [
7
+ SimpleCov::Formatter::HTMLFormatter,
8
+ Coveralls::SimpleCov::Formatter
9
+ ]
10
+ )
11
+
12
+ SimpleCov.start do
13
+ project_name 'mustermann'
14
+ minimum_coverage 100
15
+ coverage_dir '.coverage'
16
+
17
+ add_filter "/spec/"
18
+ add_filter "/support/"
19
+
20
+ Support::Projects.each do |project|
21
+ add_group project.sub('mustermann-', ''), "/#{project}/lib"
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ if RUBY_VERSION < '2.1.0'
2
+ $stderr.puts "needs Ruby 2.1.0, you're running #{RUBY_VERSION}"
3
+ exit 1
4
+ end
5
+
6
+ RUBY_ENGINE ||= 'ruby'
7
+ ENV['RACK_ENV'] = 'test'
8
+
9
+ require 'tool/warning_filter'
10
+ $-w = true
11
+
12
+ require 'rspec'
13
+ require 'rspec/its'
14
+
15
+ RSpec.configure do |config|
16
+ config.expect_with :rspec do |c|
17
+ c.syntax = [:should, :expect]
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ RSpec::Matchers.define :expand do |behavior = nil, **values|
2
+ match do |pattern|
3
+ @string ||= nil
4
+ begin
5
+ expanded = pattern.expand(behavior, values)
6
+ rescue Exception
7
+ false
8
+ else
9
+ @string ? @string == expanded : !!expanded
10
+ end
11
+ end
12
+
13
+ chain :to do |string|
14
+ @string = string
15
+ end
16
+
17
+ failure_message do |pattern|
18
+ message = "expected %p to be expandable with %p" % [pattern, values]
19
+ message << " (%p behavior)" % behavior if behavior
20
+ expanded = pattern.expand(behavior, values)
21
+ message << " and result in %p, but got %p" % [@string, expanded] if @string
22
+ message
23
+ end
24
+
25
+ failure_message_when_negated do |pattern|
26
+ "expected %p not to be expandable with %p" % [pattern, values]
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ RSpec::Matchers.define :generate_template do |template|
2
+ match { |pattern| pattern.to_templates.include? template }
3
+
4
+ failure_message do |pattern|
5
+ "expected %p to generate template %p, but only generated %s" % [
6
+ pattern, template, pattern.to_templates.map(&:inspect).join(', ')
7
+ ]
8
+ end
9
+
10
+ failure_message_when_negated do |pattern|
11
+ "expected %p not to generate template %p" % [ pattern, template ]
12
+ end
13
+ end
14
+
15
+ RSpec::Matchers.define :generate_templates do |*templates|
16
+ match { |pattern| pattern.to_templates.sort == templates.sort }
17
+
18
+ failure_message do |pattern|
19
+ "expected %p to generate templates %p, but generated %p" % [
20
+ pattern, templates.sort, pattern.to_templates.sort
21
+ ]
22
+ end
23
+
24
+ failure_message_when_negated do |pattern|
25
+ "expected %p not to generate templates %p" % [ pattern, templates ]
26
+ end
27
+ end
@@ -0,0 +1,39 @@
1
+ RSpec::Matchers.define :match do |expected|
2
+ match do |actual|
3
+ @captures ||= false
4
+ match = actual.match(expected)
5
+ match &&= @captures.all? { |k, v| match[k] == v } if @captures
6
+ match
7
+ end
8
+
9
+ chain :capturing do |captures|
10
+ @captures = captures
11
+ end
12
+
13
+ failure_message do |actual|
14
+ require 'pp'
15
+ match = actual.match(expected)
16
+ if match
17
+ key, value = @captures.detect { |k, v| match[k] != v }
18
+ message = "expected %p to capture %p as %p when matching %p, but got %p\n\nRegular Expression:\n%p" % [
19
+ actual.to_s, key, value, expected, match[key], actual.regexp
20
+ ]
21
+
22
+ if actual.respond_to? :to_ast
23
+ require 'mustermann/visualizer/tree_renderer'
24
+ tree = Mustermann::Visualizer::TreeRenderer.render(actual)
25
+ message << "\n\nAST:\n#{tree}"
26
+ end
27
+
28
+ message
29
+ else
30
+ "expected %p to match %p" % [ actual, expected ]
31
+ end
32
+ end
33
+
34
+ failure_message_when_negated do |actual|
35
+ "expected %p not to match %p" % [
36
+ actual.to_s, expected
37
+ ]
38
+ end
39
+ end
@@ -0,0 +1,42 @@
1
+ require 'timeout'
2
+
3
+ module Support
4
+ module Pattern
5
+ extend RSpec::Matchers::DSL
6
+
7
+ def pattern(pattern, options = nil, &block)
8
+ description = "pattern %p" % pattern
9
+
10
+ if options
11
+ description << " with options %p" % [options]
12
+ instance = subject_for(pattern, options)
13
+ else
14
+ instance = subject_for(pattern)
15
+ end
16
+
17
+ context description do
18
+ subject(:pattern, &instance)
19
+ its(:to_s) { should be == pattern }
20
+ its(:inspect) { should be == "#<#{described_class}:#{pattern.inspect}>" }
21
+ its(:names) { should be_an(Array) }
22
+ its(:to_templates) { should be == [pattern] } if described_class.name == "Mustermann::Template"
23
+
24
+ example 'string should be immune to external change' do
25
+ subject.to_s.replace "NOT THE PATTERN"
26
+ subject.to_s.should be == pattern
27
+ end
28
+
29
+ instance_eval(&block)
30
+ end
31
+ end
32
+
33
+ def subject_for(pattern, *args)
34
+ instance = Timeout.timeout(1) { described_class.new(pattern, *args) }
35
+ proc { instance }
36
+ rescue Timeout::Error => error
37
+ proc { raise Timeout::Error, "could not compile #{pattern.inspect} in time", error.backtrace }
38
+ rescue Exception => error
39
+ proc { raise error }
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,20 @@
1
+ module Support
2
+ module Projects
3
+ include Enumerable
4
+ extend self
5
+
6
+ def base
7
+ File.expand_path('../../../..', __FILE__)
8
+ end
9
+
10
+ def projects
11
+ @@projects ||= Dir.chdir(base) do
12
+ Dir['mustermann*/*.gemspec'].map { |f| File.dirname(f) }.sort
13
+ end
14
+ end
15
+
16
+ def each(&block)
17
+ projects.each(&block)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,63 @@
1
+ module Support
2
+ module ScanMatcher
3
+ extend RSpec::Matchers::DSL
4
+
5
+ def scan(pattern, **options)
6
+ give_scan_result(:scan, pattern, **options)
7
+ end
8
+
9
+ def check(pattern, **options)
10
+ give_scan_result(:check, pattern, **options)
11
+ end
12
+
13
+ def scan_until(pattern, **options)
14
+ give_scan_result(:scan_until, pattern, **options)
15
+ end
16
+
17
+ def check_until(pattern, **options)
18
+ give_scan_result(:check_until, pattern, **options)
19
+ end
20
+
21
+ matcher :give_scan_result do |method_name, pattern, **options|
22
+ def result_expectations
23
+ @result_expectations ||= []
24
+ end
25
+
26
+ def expect_result(description, expected, &block)
27
+ result_expectations << Proc.new do |result|
28
+ if !block.call(result)
29
+ "expected %p to %s %p matching %s" % [ result.scanner, method_name, pattern, description ]
30
+ end
31
+ end
32
+ end
33
+
34
+ match do |scanner|
35
+ scanned = scanner.public_send(method_name, pattern, **options)
36
+ scanned and result_expectations.all? { |e| !e.call(scanned) }
37
+ end
38
+
39
+ chain(:matching_substring) do |substring|
40
+ expected_result("the substring %p" % substring) { |r| r.to_s == substring }
41
+ end
42
+
43
+ chain(:matching_length) do |length|
44
+ expected_result("%d characters" % length) { |r| r.length == length }
45
+ end
46
+
47
+ chain(:matching_params) do |params|
48
+ expected_result("with params %p" % [params]) { |r| r.params == params }
49
+ end
50
+
51
+ failure_message do |scanner|
52
+ if scanned = scanner.public_send(method_name, pattern, **options)
53
+ message = result_expectations.inject(nil) { |m,e| m || e.call(scanned) }
54
+ end
55
+ message || "expected %p to %s %p" % [ scanner, method_name, pattern ]
56
+ end
57
+
58
+ failure_message_when_negated do |scanner|
59
+ "expected %p not to %s %p" % [ scanner, method_name, pattern ]
60
+ end
61
+ end
62
+ end
63
+ end