mustermann 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6b65ce2df601cc3924de9e697d1cde09019b4185
4
- data.tar.gz: f562a51c35fdcb064b2901ccfcffe87ee6417be5
3
+ metadata.gz: c4814f10c7f9b66968a8eaadb89f2eeacb328096
4
+ data.tar.gz: 69ae8b9fd3dfd3d50f0301ae10e05f168c98e5fe
5
5
  SHA512:
6
- metadata.gz: 700b01ee1c08b312d6914d386e0c3abcda85d4c630ef4c1393e57730d85f5e9debe3ce15c7f28670f51cedf2247e1e2ac6dff72d592ca1f009962fcc30a4248a
7
- data.tar.gz: 85b14c218fedd69b702fa45cefdad5f54bfe87d3eb13d8c74b717caee1e219ef64252524e2ca608b1b044447ed746b049f5a48e534612ee40ef0fa503d9c8f33
6
+ metadata.gz: 44ad20b4f6e4324732e3d6734438b4400aacbab936fedb197aee75dcd9d9522797e1c1244ff86ebc78d7855e84b8b53e440acaa9785c13e7a2c33170850b0fba
7
+ data.tar.gz: c8b2bf771c04af78b64045fe61c6188cba366472242f72286802ea7737f60d8fb0728cc946fbaadad07e1502a829f7bb94b815d7501c1b5e808bf5559eb1e360
@@ -1,7 +1,10 @@
1
1
  rvm:
2
- - 2.0.0
3
- # - ruby-head
4
- # - jruby-head
5
- #matrix:
6
- # allow_failures:
7
- # - rvm: jruby-head
2
+ - 2.0.0
3
+ - 2.1.0-preview1
4
+ - ruby-head
5
+ - jruby-head
6
+ - rbx-2.0.0
7
+ matrix:
8
+ allow_failures:
9
+ - rvm: jruby-head
10
+ - rvm: rbx-2.0.0
data/README.md CHANGED
@@ -1,6 +1,11 @@
1
1
  # The Amazing Mustermann
2
2
 
3
- [![Build Status](https://travis-ci.org/rkh/mustermann.png?branch=master)](https://travis-ci.org/rkh/mustermann) [![Coverage Status](https://coveralls.io/repos/rkh/mustermann/badge.png?branch=master)](https://coveralls.io/r/rkh/mustermann) [![Code Climate](https://codeclimate.com/github/rkh/mustermann.png)](https://codeclimate.com/github/rkh/mustermann) [![Dependency Status](https://gemnasium.com/rkh/mustermann.png)](https://gemnasium.com/rkh/mustermann) [![Gem Version](https://badge.fury.io/rb/mustermann.png)](http://badge.fury.io/rb/mustermann)
3
+ [![Build Status](https://travis-ci.org/rkh/mustermann.svg?branch=master)](https://travis-ci.org/rkh/mustermann) [![Coverage Status](http://img.shields.io/coveralls/rkh/mustermann.svg?branch=master)](https://coveralls.io/r/rkh/mustermann) [![Code Climate](http://img.shields.io/codeclimate/github/rkh/mustermann.svg)](https://codeclimate.com/github/rkh/mustermann) [![Dependency Status](https://gemnasium.com/rkh/mustermann.svg)](https://gemnasium.com/rkh/mustermann) [![Gem Version](http://img.shields.io/gem/v/mustermann.svg)](https://rubygems.org/gems/mustermann)
4
+ [![Inline docs](http://inch-ci.org/github/rkh/mustermann.svg)](http://inch-ci.org/github/rkh/mustermann)
5
+ [![Documentation](http://img.shields.io/:yard-docs-38c800.svg)](http://rubydoc.info/gems/mustermann/frames)
6
+ [![License](http://img.shields.io/:license-MIT-38c800.svg)](http://rkh.mit-license.org)
7
+ [![Badges](http://img.shields.io/:badges-9/9-38c800.svg)](http://img.shields.io)
8
+
4
9
 
5
10
  *Make sure you view the correct docs: [latest release](http://rubydoc.info/gems/mustermann/frames), [master](http://rubydoc.info/github/rkh/mustermann/master/frames).*
6
11
 
@@ -82,6 +87,16 @@ The available types are:
82
87
  <a href="#pattern_expanding">Expanding</a>
83
88
  </td>
84
89
  </tr>
90
+ <tr>
91
+ <th><a href="#regexp"><tt>regexp</tt></a></th>
92
+ <td>Regular expressions as implemented by Ruby</td>
93
+ <td><tt>/(?&lt;slug&gt;.*)</tt></td>
94
+ <td>
95
+ <a href="#ignore_unknown_options"><tt>ignore_unknown_options</tt></a>,
96
+ <a href="#uri_decode"><tt>uri_decode</tt></a>
97
+ </td>
98
+ <td></td>
99
+ </tr>
85
100
  <tr>
86
101
  <th><a href="#shell"><tt>shell</tt></th>
87
102
  <td>Unix style patterns</td>
@@ -346,6 +361,50 @@ expander = Mustermann::Expander.new("/:slug", additional_values: :append)
346
361
  expander.expand(slug: "foo", value: "bar") # => "/foo?value=bar"
347
362
  ```
348
363
 
364
+ ## Duck Typing
365
+
366
+ All methods converting string input to pattern objects will also accept any arbitrary object that implements `to_pattern`:
367
+
368
+ ``` ruby
369
+ require 'mustermann'
370
+
371
+ class MyObject
372
+ def to_pattern(**options)
373
+ Mustermann.new("/foo", **options)
374
+ end
375
+ end
376
+
377
+ object = MyObject.new
378
+ Mustermann.new(object, type: :rails) # => #<Mustermann::Rails:"/foo">
379
+ ```
380
+
381
+ It might also be that you want to call `to_pattern` yourself instead of `Mustermann.new`. You can load `mustermann/to_pattern` to implement this method for strings, regular expressions and pattern objects:
382
+
383
+ ``` ruby
384
+ require 'mustermann/to_pattern'
385
+
386
+ "/foo".to_pattern # => #<Mustermann::Sinatra:"/foo">
387
+ "/foo".to_pattern(type: :rails) # => #<Mustermann::Rails:"/foo">
388
+ %r{/foo}.to_pattern # => #<Mustermann::Regular:"\\/foo">
389
+ "/foo".to_pattern.to_pattern # => #<Mustermann::Sinatra:"/foo">
390
+ ```
391
+
392
+ You can also use the `Mustermann::ToPattern` mixin to easily add `to_pattern` to your own objects:
393
+
394
+ ``` ruby
395
+ require 'mustermann/to_pattern'
396
+
397
+ class MyObject
398
+ include Mustermann::ToPattern
399
+
400
+ def to_s
401
+ "/foo"
402
+ end
403
+ end
404
+
405
+ MyObject.new.to_pattern # => #<Mustermann::Sinatra:"/foo">
406
+ ```
407
+
349
408
  ## Partial Loading and Thread Safety
350
409
 
351
410
  Pattern objects are generally assumed to be thread-safe. You can easily match strings against the same pattern object concurrently.
@@ -481,7 +540,17 @@ By setting `ignore_unknown_options` to `true`, it will happily ignore the option
481
540
 
482
541
  ### `identity`
483
542
 
484
- Patterns that are no real patterns, just string matching.
543
+ Identity patterns are strings that have to match the input exactly.
544
+
545
+ ``` ruby
546
+ require 'mustermann'
547
+
548
+ pattern = Mustermann.new('/:example', type: :identity)
549
+ pattern === "/foo.bar" # => false
550
+ pattern === "/:example" # => true
551
+ pattern.params("/foo.bar") # => nil
552
+ pattern.params("/:example") # => {}
553
+ ```
485
554
 
486
555
  <table>
487
556
  <thead>
@@ -502,6 +571,28 @@ Patterns that are no real patterns, just string matching.
502
571
 
503
572
  Patterns with the syntax used in Rails route definitions.
504
573
 
574
+ ``` ruby
575
+ require 'mustermann'
576
+
577
+ pattern = Mustermann.new('/:example', type: :rails)
578
+ pattern === "/foo.bar" # => true
579
+ pattern === "/foo/bar" # => false
580
+ pattern.params("/foo.bar") # => { "example" => "foo.bar" }
581
+ pattern.params("/foo/bar") # => nil
582
+
583
+ pattern = Mustermann.new('/:example(/:optional)', type: :rails)
584
+ pattern === "/foo.bar" # => true
585
+ pattern === "/foo/bar" # => true
586
+ pattern.params("/foo.bar") # => { "example" => "foo.bar", "optional" => nil }
587
+ pattern.params("/foo/bar") # => { "example" => "foo", "optional" => "bar" }
588
+
589
+ pattern = Mustermann.new('/*example', type: :rails)
590
+ pattern === "/foo.bar" # => true
591
+ pattern === "/foo/bar" # => true
592
+ pattern.params("/foo.bar") # => { "example" => "foo.bar" }
593
+ pattern.params("/foo/bar") # => { "example" => "foo/bar" }
594
+ ```
595
+
505
596
  <table>
506
597
  <thead>
507
598
  <tr>
@@ -540,10 +631,64 @@ Patterns with the syntax used in Rails route definitions.
540
631
  </tbody>
541
632
  </table>
542
633
 
634
+ ### `regexp`
635
+
636
+ Regular expression patterns, as used implemented by Ruby. Do not include characters for matching beginning or end of string/line.
637
+ This pattern type is also known as `regular` and the pattern class is `Mustermann::Regular` (located in `mustermann/regular`).
638
+
639
+ ``` ruby
640
+ require 'mustermann'
641
+
642
+ pattern = Mustermann.new('/(?<example>.*)', type: :regexp)
643
+ pattern === "/foo.bar" # => true
644
+ pattern === "/foo/bar" # => true
645
+ pattern.params("/foo.bar") # => { "example" => "foo.bar" }
646
+ pattern.params("/foo/bar") # => { "example" => "foo/bar" }
647
+ ```
648
+
649
+ <table>
650
+ <thead>
651
+ <tr>
652
+ <th>Syntax Element</th>
653
+ <th>Description</th>
654
+ </tr>
655
+ </thead>
656
+ <tbody>
657
+ <tr>
658
+ <td><i>any string</i></td>
659
+ <td>Interpreted as regular expression.</td>
660
+ </tr>
661
+ </tbody>
662
+ </table>
663
+
664
+ It is also possible to turn a proper Regexp instance into a pattern object by passing it to `Mustermann.new`:
665
+
666
+ ``` ruby
667
+ require 'mustermann'
668
+ Mustermann.new(/(?<example>.*)/).params("input") # => { "example" => "input" }
669
+ ```
670
+
543
671
  ### `shell`
544
672
 
545
673
  Shell patterns, as used in Bash or with `Dir.glob`.
546
674
 
675
+ ``` ruby
676
+ require 'mustermann'
677
+
678
+ pattern = Mustermann.new('/*', type: :shell)
679
+ pattern === "/foo.bar" # => true
680
+ pattern === "/foo/bar" # => false
681
+
682
+ pattern = Mustermann.new('/**/*', type: :shell)
683
+ pattern === "/foo.bar" # => true
684
+ pattern === "/foo/bar" # => true
685
+
686
+ pattern = Mustermann.new('/{foo,bar}', type: :shell)
687
+ pattern === "/foo" # => true
688
+ pattern === "/bar" # => true
689
+ pattern === "/baz" # => false
690
+ ```
691
+
547
692
  <table>
548
693
  <thead>
549
694
  <tr>
@@ -581,7 +726,29 @@ Shell patterns, as used in Bash or with `Dir.glob`.
581
726
 
582
727
  ### `simple`
583
728
 
584
- Patterns as used by Sinatra 1.3. Useful for porting an application that relies on this behavior to a later Sinatra version and to make sure [Sinatra 2.0](#sinatra) patterns do not decrease performance.
729
+ Patterns as used by Sinatra 1.3. Useful for porting an application that relies on this behavior to a later Sinatra version and to make sure [Sinatra 2.0](#sinatra) patterns do not decrease performance. Simple patterns internally use the same code older Sinatra versions used for compiling the pattern. Error messages for broken patterns will therefore not be as informative as for other pattern implementations.
730
+
731
+ ``` ruby
732
+ require 'mustermann'
733
+
734
+ pattern = Mustermann.new('/:example', type: :simple)
735
+ pattern === "/foo.bar" # => true
736
+ pattern === "/foo/bar" # => false
737
+ pattern.params("/foo.bar") # => { "example" => "foo.bar" }
738
+ pattern.params("/foo/bar") # => nil
739
+
740
+ pattern = Mustermann.new('/:example/?:optional?', type: :simple)
741
+ pattern === "/foo.bar" # => true
742
+ pattern === "/foo/bar" # => true
743
+ pattern.params("/foo.bar") # => { "example" => "foo.bar", "optional" => nil }
744
+ pattern.params("/foo/bar") # => { "example" => "foo", "optional" => "bar" }
745
+
746
+ pattern = Mustermann.new('/*', type: :simple)
747
+ pattern === "/foo.bar" # => true
748
+ pattern === "/foo/bar" # => true
749
+ pattern.params("/foo.bar") # => { "splat" => ["foo.bar"] }
750
+ pattern.params("/foo/bar") # => { "splat" => ["foo/bar"] }
751
+ ```
585
752
 
586
753
  <table>
587
754
  <thead>
@@ -629,6 +796,40 @@ Patterns as used by Sinatra 1.3. Useful for porting an application that relies o
629
796
 
630
797
  Sinatra 2.0 style patterns. The default used by Mustermann.
631
798
 
799
+ ``` ruby
800
+ require 'mustermann'
801
+
802
+ pattern = Mustermann.new('/:example')
803
+ pattern === "/foo.bar" # => true
804
+ pattern === "/foo/bar" # => false
805
+ pattern.params("/foo.bar") # => { "example" => "foo.bar" }
806
+ pattern.params("/foo/bar") # => nil
807
+
808
+ pattern = Mustermann.new('/\:example')
809
+ pattern === "/foo.bar" # => false
810
+ pattern === "/:example" # => true
811
+ pattern.params("/foo.bar") # => nil
812
+ pattern.params("/:example") # => {}
813
+
814
+ pattern = Mustermann.new('/:example(/:optional)?')
815
+ pattern === "/foo.bar" # => true
816
+ pattern === "/foo/bar" # => true
817
+ pattern.params("/foo.bar") # => { "example" => "foo.bar", "optional" => nil }
818
+ pattern.params("/foo/bar") # => { "example" => "foo", "optional" => "bar" }
819
+
820
+ pattern = Mustermann.new('/*')
821
+ pattern === "/foo.bar" # => true
822
+ pattern === "/foo/bar" # => true
823
+ pattern.params("/foo.bar") # => { "splat" => ["foo.bar"] }
824
+ pattern.params("/foo/bar") # => { "splat" => ["foo/bar"] }
825
+
826
+ pattern = Mustermann.new('/*example')
827
+ pattern === "/foo.bar" # => true
828
+ pattern === "/foo/bar" # => true
829
+ pattern.params("/foo.bar") # => { "example" => "foo.bar" }
830
+ pattern.params("/foo/bar") # => { "example" => "foo/bar" }
831
+ ```
832
+
632
833
  <table>
633
834
  <thead>
634
835
  <tr>
@@ -644,6 +845,12 @@ Sinatra 2.0 style patterns. The default used by Mustermann.
644
845
  Capture behavior can be modified with <a href="#capture"><tt>capture</tt></a> and <a href="#greedy"><tt>greedy</tt></a> option.
645
846
  </td>
646
847
  </tr>
848
+ <tr>
849
+ <td><b>*</b><i>name</i></td>
850
+ <td>
851
+ Captures anything in a non-greedy fashion. Capture is named <i>name</i>.
852
+ </td>
853
+ </tr>
647
854
  <tr>
648
855
  <td><b>*</b></td>
649
856
  <td>
@@ -685,6 +892,19 @@ Parses fully expanded URI templates as specified by [RFC 6570](http://tools.ietf
685
892
 
686
893
  Note that it differs from URI templates in that it takes the unescaped version of special character instead of the escaped version.
687
894
 
895
+ ``` ruby
896
+ require 'mustermann'
897
+
898
+ pattern = Mustermann.new('/{example}', type: :template)
899
+ pattern === "/foo.bar" # => true
900
+ pattern === "/foo/bar" # => false
901
+ pattern.params("/foo.bar") # => { "example" => "foo.bar" }
902
+ pattern.params("/foo/bar") # => nil
903
+
904
+ pattern = Mustermann.new("{/segments*}/{page}{.ext,cmpr:2}", type: :template)
905
+ pattern.params("/a/b/c.tar.gz") # => {"segments"=>["a","b"], "page"=>"c", "ext"=>"tar", "cmpr"=>"gz"}
906
+ ```
907
+
688
908
  <table>
689
909
  <thead>
690
910
  <tr>
@@ -718,11 +938,6 @@ The operators `+` and `#` will always match non-greedy, whereas all other operat
718
938
  All modifiers and operators are supported. However, it does not parse lists as single values without the *explode* modifier (aka *star*).
719
939
  Parametric operators (`;`, `?` and `&`) currently only match parameters in given order.
720
940
 
721
- ``` ruby
722
- pattern = Mustermann.new("{/segments*}/{page}{.ext,cmpr:2}", type: :template)
723
- pattern.params("/a/b/c.tar.gz") # => {"segments"=>["a","b"], "page"=>"c", "ext"=>"tar", "cmpr"=>"gz"}
724
- ```
725
-
726
941
  Please keep the following in mind:
727
942
 
728
943
  > "Some URI Templates can be used in reverse for the purpose of variable matching: comparing the template to a fully formed URI in order to extract the variable parts from that URI and assign them to the named variables. Variable matching only works well if the template expressions are delimited by the beginning or end of the URI or by characters that cannot be part of the expansion, such as reserved characters surrounding a simple string expression. In general, regular expression languages are better suited for variable matching."
@@ -733,6 +948,19 @@ you should set `uri_decode` to `false` in order to conform with the specificatio
733
948
 
734
949
  If you are looking for an alternative implementation that also supports expanding, check out [addressable](http://addressable.rubyforge.org/).
735
950
 
951
+ ## Mapper
952
+
953
+ You can use a mapper to transform strings according to two or more mappings:
954
+
955
+ ``` ruby
956
+ require 'mustermann/mapper'
957
+
958
+ mapper = Mustermann::Mapper.new("/:page(.:format)?" => ["/:page/view.:format", "/:page/view.html"])
959
+ mapper['/foo'] # => "/foo/view.html"
960
+ mapper['/foo.xml'] # => "/foo/view.xml"
961
+ mapper['/foo/bar'] # => "/foo/bar"
962
+ ```
963
+
736
964
  ## Routers
737
965
 
738
966
  Mustermann comes with basic router implementations that will call certain callbacks depending on the input.
@@ -757,7 +985,7 @@ This is not a full replacement for Rails, Sinatra, Cuba, etc, as it only cares a
757
985
  ``` ruby
758
986
  require 'mustermann/router/rack'
759
987
 
760
- router = Mustermann::Router::Rack do
988
+ router = Mustermann::Router::Rack.new do
761
989
  on '/' do |env|
762
990
  [200, {'Content-Type' => 'text/plain'}, ['Hello World!']]
763
991
  end
@@ -795,6 +1023,16 @@ As there has been no stable release yet, the API might still change, though I co
795
1023
 
796
1024
  ### Development Releases
797
1025
 
1026
+ * **Mustermann 0.3.0** (2014-08-18)
1027
+ * More Infos:
1028
+ [RubyGems.org](http://rubygems.org/gems/mustermann/versions/0.3.0),
1029
+ [RubyDoc.info](http://rubydoc.info/gems/mustermann/0.3.0/frames),
1030
+ [GitHub.com](https://github.com/rkh/mustermann/tree/v0.3.0)
1031
+ * Add `regexp` pattern.
1032
+ * Add named splats to Sinatra patterns.
1033
+ * Add `Mustermann::Mapper`.
1034
+ * Improve duck typing support.
1035
+ * Improve documentation.
798
1036
  * **Mustermann 0.2.0** (2013-08-24)
799
1037
  * More Infos:
800
1038
  [RubyGems.org](http://rubygems.org/gems/mustermann/versions/0.2.0),
@@ -832,6 +1070,5 @@ As there has been no stable release yet, the API might still change, though I co
832
1070
 
833
1071
  ### Upcoming Releases
834
1072
 
835
- * **Mustermann 0.3.0** (next release with new features)
836
1073
  * **Mustermann 1.0.0** (before Sinatra 2.0)
837
1074
  * First stable release.
@@ -1,15 +1,22 @@
1
+ require 'mustermann/pattern'
2
+
1
3
  # Namespace and main entry point for the Mustermann library.
2
4
  #
3
5
  # Under normal circumstances the only external API entry point you should be using is {Mustermann.new}.
4
6
  module Mustermann
5
- # @param [String] string The string representation of the new pattern
7
+ # @param [String, Pattern, Regexp, #to_pattern] input The representation of the new pattern
6
8
  # @param [Hash] options The options hash
7
9
  # @return [Mustermann::Pattern] pattern corresponding to string.
8
10
  # @raise (see [])
9
11
  # @raise (see Mustermann::Pattern.new)
10
12
  # @see file:README.md#Types_and_Options "Types and Options" in the README
11
- def self.new(string, type: :sinatra, **options)
12
- options.any? ? self[type].new(string, **options) : self[type].new(string)
13
+ def self.new(input, type: :sinatra, **options)
14
+ case input
15
+ when Pattern then input
16
+ when Regexp then self[:regexp].new(input, **options)
17
+ when String then self[type].new(input, **options)
18
+ else input.to_pattern(type: type, **options)
19
+ end
13
20
  end
14
21
 
15
22
  # Maps a type to its factory.
@@ -27,9 +34,9 @@ module Mustermann
27
34
  end
28
35
 
29
36
  # @!visibility private
30
- def self.register(identifier = nil, constant = identifier.to_s.capitalize, load: "mustermann/#{identifier}")
37
+ def self.register(*identifiers, constant: identifiers.first.to_s.capitalize, load: "mustermann/#{identifiers.first}")
31
38
  @register ||= {}
32
- @register[identifier] = [constant, load] if identifier
39
+ identifiers.each { |i| @register[i] = [constant, load] }
33
40
  @register
34
41
  end
35
42
 
@@ -42,6 +49,7 @@ module Mustermann
42
49
 
43
50
  register :identity
44
51
  register :rails
52
+ register :regular, :regexp
45
53
  register :shell
46
54
  register :simple
47
55
  register :sinatra
@@ -59,10 +59,17 @@ module Mustermann
59
59
  @mappings ||= {}
60
60
  end
61
61
 
62
+ # all the known keys
63
+ # @!visibility private
64
+ def keys
65
+ @keys ||= []
66
+ end
67
+
62
68
  # add a tree for expansion
63
69
  # @!visibility private
64
70
  def add(ast)
65
71
  translate(ast).each do |keys, pattern, filter|
72
+ self.keys.concat(keys).uniq!
66
73
  mappings[keys.uniq.sort] ||= [keys, pattern, filter]
67
74
  end
68
75
  end
@@ -81,6 +88,14 @@ module Mustermann
81
88
  pattern % values.values_at(*keys)
82
89
  end
83
90
 
91
+ # @see Mustermann::Pattern#expandable?
92
+ # @!visibility private
93
+ def expandable?(values)
94
+ values = values.keys if values.respond_to? :keys
95
+ values = values.sort if values.respond_to? :sort
96
+ mappings.include? values
97
+ end
98
+
84
99
  # @see Mustermann::Expander#with_rest
85
100
  # @!visibility private
86
101
  def expandable_keys(keys)