Class: Bunto::URL

Inherits:
Object
  • Object
show all
Defined in:
lib/bunto/url.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ URL

options - One of :permalink or :template must be supplied.

:template     - The String used as template for URL generation,
                for example "/:path/:basename:output_ext", where
                a placeholder is prefixed with a colon.
:placeholders - A hash containing the placeholders which will be
                replaced when used inside the template. E.g.
                { "year" => Time.now.strftime("%Y") } would replace
                the placeholder ":year" with the current year.
:permalink    - If supplied, no URL will be generated from the
                template. Instead, the given permalink will be
                used as URL.


25
26
27
28
29
30
31
32
33
# File 'lib/bunto/url.rb', line 25

def initialize(options)
  @template     = options[:template]
  @placeholders = options[:placeholders] || {}
  @permalink    = options[:permalink]

  if (@template || @permalink).nil?
    raise ArgumentError, "One of :template or :permalink must be supplied."
  end
end

Class Method Details

.escape_path(path) ⇒ Object

Escapes a path to be a valid URL path segment

path - The path to be escaped.

Examples:

URL.escape_path("/a b")
# => "/a%20b"

Returns the escaped path.



115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/bunto/url.rb', line 115

def self.escape_path(path)
  # Because URI.escape doesn't escape "?", "[" and "]" by default,

  # specify unsafe string (except unreserved, sub-delims, ":", "@" and "/").

  #

  # URI path segment is defined in RFC 3986 as follows:

  #   segment       = *pchar

  #   pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"

  #   unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"

  #   pct-encoded   = "%" HEXDIG HEXDIG

  #   sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"

  #                 / "*" / "+" / "," / ";" / "="

  URI.escape(path, %r{[^a-zA-Z\d\-._~!$&'()*+,;=:@\/]}).encode("utf-8")
end

.unescape_path(path) ⇒ Object

Unescapes a URL path segment

path - The path to be unescaped.

Examples:

URL.unescape_path("/a%20b")
# => "/a b"

Returns the unescaped path.



139
140
141
# File 'lib/bunto/url.rb', line 139

def self.unescape_path(path)
  URI.unescape(path.encode("utf-8"))
end

Instance Method Details

#generate_url(template) ⇒ Object

Internal: Generate the URL by replacing all placeholders with their respective values in the given template

Returns the unsanitized String URL



67
68
69
70
71
72
73
# File 'lib/bunto/url.rb', line 67

def generate_url(template)
  if @placeholders.is_a? Drops::UrlDrop
    generate_url_from_drop(template)
  else
    generate_url_from_hash(template)
  end
end

#generate_url_from_drop(template) ⇒ Object



87
88
89
90
91
92
93
94
95
96
# File 'lib/bunto/url.rb', line 87

def generate_url_from_drop(template)
  template.gsub(%r!:([a-z_]+)!) do |match|
    replacement = @placeholders.public_send(match.sub(":".freeze, "".freeze))
    if replacement.nil?
      "".freeze
    else
      self.class.escape_path(replacement)
    end
  end.gsub(%r!//!, "/".freeze)
end

#generate_url_from_hash(template) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
# File 'lib/bunto/url.rb', line 75

def generate_url_from_hash(template)
  @placeholders.inject(template) do |result, token|
    break result if result.index(":").nil?
    if token.last.nil?
      # Remove leading "/" to avoid generating urls with `//`

      result.gsub(%r!/:#{token.first}!, "")
    else
      result.gsub(%r!:#{token.first}!, self.class.escape_path(token.last))
    end
  end
end

Generates a URL from the permalink

Returns the _unsanitized String URL



52
53
54
# File 'lib/bunto/url.rb', line 52

def generated_permalink
  (@generated_permalink ||= generate_url(@permalink)) if @permalink
end

#generated_urlObject

Generates a URL from the template

Returns the unsanitized String URL



59
60
61
# File 'lib/bunto/url.rb', line 59

def generated_url
  @generated_url ||= generate_url(@template)
end

#sanitize_url(str) ⇒ Object

Returns a sanitized String URL, stripping “../../” and multiples of “/”, as well as the beginning “/” so we can enforce and ensure it.



101
102
103
# File 'lib/bunto/url.rb', line 101

def sanitize_url(str)
  "/" + str.gsub(%r!/{2,}!, "/").gsub(%r!\.+/|\A/+!, "")
end

#to_sObject

The generated relative URL of the resource

Returns the String URL Raises a Bunto::Errors::InvalidURLError if the relative URL contains a colon



39
40
41
42
43
44
45
46
47
# File 'lib/bunto/url.rb', line 39

def to_s
  sanitized_url = sanitize_url(generated_permalink || generated_url)
  if sanitized_url.include?(":")
    raise Bunto::Errors::InvalidURLError,
      "The URL #{sanitized_url} is invalid because it contains a colon."
  else
    sanitized_url
  end
end