redhead 0.0.1
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.
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +445 -0
- data/lib/redhead.rb +37 -0
- data/lib/redhead/header.rb +83 -0
- data/lib/redhead/header_set.rb +134 -0
- data/lib/redhead/redhead_string.rb +62 -0
- data/rakefile +11 -0
- data/test/header_set_spec.rb +344 -0
- data/test/header_spec.rb +270 -0
- data/test/redhead_spec.rb +1 -0
- data/test/redhead_string_spec.rb +114 -0
- data/test/test_helper.rb +1 -0
- metadata +87 -0
data/lib/redhead.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Copyright (c) 2010 Adam Prescott
|
2
|
+
# Licensed under the MIT license. See LICENSE.
|
3
|
+
|
4
|
+
module Redhead
|
5
|
+
|
6
|
+
# The character used to separate raw header names from their values.
|
7
|
+
HEADER_NAME_VALUE_SEPARATOR_CHARACTER = ":"
|
8
|
+
|
9
|
+
# The actual pattern to split header name from value. Uses the above character.
|
10
|
+
HEADER_NAME_VALUE_SEPARATOR_PATTERN = /\s*#{HEADER_NAME_VALUE_SEPARATOR_CHARACTER}\s*/
|
11
|
+
|
12
|
+
# The separator between header lines and regular body content.
|
13
|
+
HEADERS_SEPARATOR = "\n\n"
|
14
|
+
|
15
|
+
# The actual pattern used to split headers from content.
|
16
|
+
HEADERS_SEPARATOR_PATTERN = /#{HEADERS_SEPARATOR}/m
|
17
|
+
|
18
|
+
# The default code to convert a given key to a raw header name.
|
19
|
+
TO_RAW = lambda { |key| key.to_s.split(/_/).map(&:capitalize).join("-") }
|
20
|
+
|
21
|
+
# The default code to convert a given raw header name to a key.
|
22
|
+
TO_KEY = lambda { |raw| raw.split(/[^a-z_]+/i).join("_").downcase.to_sym }
|
23
|
+
|
24
|
+
# Method wrapping TO_RAW, to allow overriding for customisation.
|
25
|
+
def self.to_raw
|
26
|
+
TO_RAW
|
27
|
+
end
|
28
|
+
|
29
|
+
# Method wrapping TO_KEY, to allow overriding for customisation.
|
30
|
+
def self.to_key
|
31
|
+
TO_KEY
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
require "redhead/header"
|
36
|
+
require "redhead/header_set"
|
37
|
+
require "redhead/redhead_string"
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Redhead
|
2
|
+
class Header
|
3
|
+
attr_accessor :key, :raw, :value
|
4
|
+
attr_writer :to_key, :to_raw
|
5
|
+
|
6
|
+
def initialize(key, raw, value)
|
7
|
+
@key = key
|
8
|
+
@raw = raw
|
9
|
+
@value = value
|
10
|
+
end
|
11
|
+
|
12
|
+
# Parses a string representing a header. Uses HEADER_NAME_VALUE_SEPARATOR_PATTERN
|
13
|
+
# to determine the name and value parts of the string.
|
14
|
+
#
|
15
|
+
# With a given block, the parsed raw header name is passed to the block and the result is
|
16
|
+
# used as the key name. If no block is given, then the default is used to create the key
|
17
|
+
# name.
|
18
|
+
def self.parse(header_string, &block)
|
19
|
+
header_string =~ HEADER_NAME_VALUE_SEPARATOR_PATTERN
|
20
|
+
raw = $`
|
21
|
+
value = $'
|
22
|
+
|
23
|
+
to_key_block = block || Redhead.to_key
|
24
|
+
key = to_key_block[raw]
|
25
|
+
|
26
|
+
header = new(key, raw, value)
|
27
|
+
|
28
|
+
header
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the header as a string. If raw_name is given, this value is used as the raw header
|
32
|
+
# name. If raw_name is not given, do one of two things:
|
33
|
+
#
|
34
|
+
# * If a block is given, pass #key to the block and use the result as the raw header name.
|
35
|
+
# * If a block is not given, use #raw as the raw header name.
|
36
|
+
def to_s(raw_name = nil)
|
37
|
+
r = raw_name || (block_given? ? yield(key) : raw)
|
38
|
+
"#{r}#{Redhead::HEADER_NAME_VALUE_SEPARATOR_CHARACTER} #{value}"
|
39
|
+
end
|
40
|
+
|
41
|
+
# Does the same thing as #to_s, but instead of calling #raw in the last case, it calls #raw!.
|
42
|
+
def to_s!(raw_name = nil)
|
43
|
+
r = raw_name || (block_given? ? yield(key) : raw!)
|
44
|
+
"#{r}#{Redhead::HEADER_NAME_VALUE_SEPARATOR_CHARACTER} #{value}"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Calls #to_key with #raw as the argument.
|
48
|
+
def key!
|
49
|
+
to_key[raw]
|
50
|
+
end
|
51
|
+
|
52
|
+
# Calls #to_raw with #key as the argument. By-passes the stored raw header name and reproduces
|
53
|
+
# it with #to_raw dynamically.
|
54
|
+
def raw!
|
55
|
+
to_raw[key]
|
56
|
+
end
|
57
|
+
|
58
|
+
def inspect
|
59
|
+
"{ #{key.inspect} => #{value.inspect} }"
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns true if other_header has the same raw header name and value as self.
|
63
|
+
def ==(other_header)
|
64
|
+
raw == other_header.raw &&
|
65
|
+
value == other_header.value
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns the Proc object used to convert keys to raw header names. Defaults to Redhead.to_raw.
|
69
|
+
def to_raw
|
70
|
+
@to_raw || Redhead.to_raw
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns the Proc object used to convert keys to raw header names. Defaults to Redhead.to_raw.
|
74
|
+
def to_key
|
75
|
+
@to_key || Redhead.to_key
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns true if to_raw[to_key[raw]] == raw, otherwise, false.
|
79
|
+
def reversible?
|
80
|
+
to_raw[to_key[raw]] == raw
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module Redhead
|
2
|
+
class HeaderSet
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
# Sets the headers of the set to _headers_. _headers_ is assumed to be ordered.
|
6
|
+
def initialize(headers)
|
7
|
+
@headers = headers
|
8
|
+
end
|
9
|
+
|
10
|
+
# Parses lines of header strings with Header.parse. Returns a new HeaderSet object
|
11
|
+
# for the parsed headers.
|
12
|
+
def self.parse(header_string, &block)
|
13
|
+
headers = []
|
14
|
+
header_string.split("\n").each do |str|
|
15
|
+
headers << Redhead::Header.parse(str, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
new(headers)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Yields each header in the set.
|
22
|
+
def each
|
23
|
+
@headers.each { |h| yield h }
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns true if the set of headers is empty.
|
27
|
+
def empty?
|
28
|
+
@headers.empty?
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the first header found which has Header#key matching _key_.
|
32
|
+
def [](key)
|
33
|
+
@headers.find { |header| header.key == key }
|
34
|
+
end
|
35
|
+
|
36
|
+
# If there is a header in the set with a key matching _key_, then set its value to _value_.
|
37
|
+
# If there is no header matching _key_, create a new header with the given key and value,
|
38
|
+
# with a raw header equal to to_raw[key]. Sets the new header's to_raw to self#to_raw.
|
39
|
+
def []=(key, value)
|
40
|
+
h = self[key]
|
41
|
+
if h
|
42
|
+
h.value = value
|
43
|
+
else
|
44
|
+
new_header = Redhead::Header.new(key, to_raw[key], value)
|
45
|
+
new_header.to_raw = to_raw
|
46
|
+
self << new_header
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Adds _header_ to the set of headers.
|
51
|
+
def <<(header)
|
52
|
+
@headers << header
|
53
|
+
end
|
54
|
+
|
55
|
+
# Similar to #[]= but allows manually setting the value of Header#raw to _raw_.
|
56
|
+
def add(key, value, raw = nil)
|
57
|
+
new_header = Redhead::Header.new(key, raw || to_raw[key], value)
|
58
|
+
new_header.to_raw = to_raw
|
59
|
+
self << new_header
|
60
|
+
new_header
|
61
|
+
end
|
62
|
+
|
63
|
+
# Removes any headers with key names matching _key_ from the set.
|
64
|
+
def delete(key)
|
65
|
+
header = self[key]
|
66
|
+
@headers.reject! { |header| header.key == key } ? header : nil
|
67
|
+
end
|
68
|
+
|
69
|
+
# Calls #to_s on each header in the set, joining the result with newlines.
|
70
|
+
#
|
71
|
+
# If _hash_ has a key matching a header in the set, passes the value for that key in the hash
|
72
|
+
# to Header#to_s. If _hash_ has no key for the header being iterated over, passes the given
|
73
|
+
# block to Header#to_s instead.
|
74
|
+
def to_s(hash = {}, &block)
|
75
|
+
return @headers.map { |header| header.to_s }.join("\n") if hash.empty? && !block_given?
|
76
|
+
|
77
|
+
@headers.map do |header|
|
78
|
+
if hash.has_key?(header.key)
|
79
|
+
header.to_s(hash[header.key])
|
80
|
+
else
|
81
|
+
header.to_s(&block)
|
82
|
+
end
|
83
|
+
end.join("\n")
|
84
|
+
end
|
85
|
+
|
86
|
+
# If a block is given, passes the block to Header#to_s! otherwise passes #to_raw instead. Joins
|
87
|
+
# the result with newlines.
|
88
|
+
def to_s!(&block)
|
89
|
+
blk = block || to_raw
|
90
|
+
@headers.map { |header| header.to_s!(&blk) }.join("\n")
|
91
|
+
end
|
92
|
+
|
93
|
+
# Returns true if Header#reversible? is true for each header in the set, otherwise false.
|
94
|
+
def reversible?
|
95
|
+
all? { |header| header.reversible? }
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns the Proc to be used to convert key names to raw header names. Defaults to Redhead.to_raw.
|
99
|
+
def to_raw
|
100
|
+
@to_raw || Redhead.to_raw
|
101
|
+
end
|
102
|
+
|
103
|
+
# Sets HeaderSet#to_raw to _new_to_raw_. Sets Header#to_raw for each header in the set to _new_to_raw_.
|
104
|
+
def to_raw=(new_to_raw)
|
105
|
+
@to_raw = new_to_raw
|
106
|
+
each { |header| header.to_raw = new_to_raw }
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns the Proc to be used to convert raw header names to key names. Defaults to Redhead.to_key.
|
110
|
+
def to_key
|
111
|
+
@to_key || Redhead.to_key
|
112
|
+
end
|
113
|
+
|
114
|
+
# Sets HeaderSet#to_raw to _new_to_raw_. Sets Header#to_raw for each header in the set to _new_to_raw_.
|
115
|
+
def to_key=(new_to_key)
|
116
|
+
@to_key = new_to_key
|
117
|
+
each { |header| header.to_key = new_to_key }
|
118
|
+
end
|
119
|
+
|
120
|
+
def inspect
|
121
|
+
"{ #{@headers.map { |header| header.inspect }.join(", ")} }"
|
122
|
+
end
|
123
|
+
|
124
|
+
# Returns true if, for each header in the set, there is a header in _other_ for which header#==(other_header)
|
125
|
+
# is true. Otherwise, returns false.
|
126
|
+
def ==(other)
|
127
|
+
@headers.all? do |header|
|
128
|
+
other.find do |other_header|
|
129
|
+
header == other_header
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require "delegate"
|
2
|
+
|
3
|
+
module Redhead
|
4
|
+
class String < SimpleDelegator
|
5
|
+
attr_reader :headers, :string
|
6
|
+
|
7
|
+
class << self
|
8
|
+
alias_method :[], :new
|
9
|
+
end
|
10
|
+
|
11
|
+
# Takes _string_, splits the headers from the content using HEADERS_SEPARATOR_PATTERN, then
|
12
|
+
# creates the headers by calling HeaderSet.parse, passing in _block_. Sets #to_key to _block_,
|
13
|
+
# and calls super with the main body content as an argument.
|
14
|
+
def initialize(string, &block)
|
15
|
+
string =~ HEADERS_SEPARATOR_PATTERN
|
16
|
+
@string = $'
|
17
|
+
super(@string)
|
18
|
+
|
19
|
+
@headers = Redhead::HeaderSet.parse($`, &block)
|
20
|
+
@headers.to_key = block
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the main body content wrapped in the Redhead String object.
|
24
|
+
def to_s
|
25
|
+
__getobj__
|
26
|
+
end
|
27
|
+
|
28
|
+
def inspect
|
29
|
+
"+#{string.inspect}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns true if self.headers == other.headers and self.string == other.string.
|
33
|
+
def ==(other)
|
34
|
+
headers == other.headers && string == other.string
|
35
|
+
end
|
36
|
+
|
37
|
+
# Modifies the headers in the set, using the given _hash_, which has the form
|
38
|
+
#
|
39
|
+
# { :some_header => { :raw => a, :key => b }, :another_header => ..., ... }
|
40
|
+
#
|
41
|
+
# Change the header with key :some_header such that its new raw name is _a_ and its new key name
|
42
|
+
# is _b_. Returns a HeaderSet object containing the changed Header objects.
|
43
|
+
def headers!(hash)
|
44
|
+
changing = headers.select { |header| hash.has_key?(header.key) }
|
45
|
+
|
46
|
+
# modifies its elements!
|
47
|
+
changing.each do |header|
|
48
|
+
new_values = hash[header.key]
|
49
|
+
header.raw = new_values[:raw] if new_values[:raw]
|
50
|
+
header.key = new_values[:key] if new_values[:key]
|
51
|
+
end
|
52
|
+
|
53
|
+
Redhead::HeaderSet.new(changing)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def __getobj__
|
60
|
+
string
|
61
|
+
end
|
62
|
+
end
|
data/rakefile
ADDED
@@ -0,0 +1,344 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
describe Redhead::HeaderSet do
|
4
|
+
before(:each) do
|
5
|
+
@headers = []
|
6
|
+
("a".."c").map { |e| @headers << Redhead::Header.new(e.to_sym, "header_#{e}", "value_#{e}") }
|
7
|
+
@full_header_set_string = ("a".."c").map { |e| "header_#{e}: value_#{e}" }.join("\n")
|
8
|
+
@header = @headers.first
|
9
|
+
@first_header_key = :a
|
10
|
+
@header_set = Redhead::HeaderSet.new(@headers)
|
11
|
+
@default_to_raw = Redhead.to_raw
|
12
|
+
@default_to_key = Redhead.to_key
|
13
|
+
|
14
|
+
@reversible_headers = Redhead::HeaderSet.parse("A-Header: one\nA-Header-Two: two")
|
15
|
+
@irreversible_headers = Redhead::HeaderSet.parse("a_header: one\na_header_two: two")
|
16
|
+
end
|
17
|
+
|
18
|
+
context "as a class" do
|
19
|
+
describe ".parse" do
|
20
|
+
it "calls Header.parse on each header line, to create a set of headers" do
|
21
|
+
string = @full_header_set_string + Redhead::HEADERS_SEPARATOR + "some content goes here"
|
22
|
+
header_lines = @full_header_set_string.split("\n")
|
23
|
+
parsed_header_set = Redhead::HeaderSet.new(header_lines.map { |header_line| Redhead::Header.parse(header_line) })
|
24
|
+
Redhead::HeaderSet.parse(@full_header_set_string).should == parsed_header_set
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "with a block" do
|
29
|
+
it "uses the given block as to_key" do
|
30
|
+
Redhead::HeaderSet.parse(@full_header_set_string) { :foo }.each { |h| h.key.should == :foo }
|
31
|
+
end
|
32
|
+
|
33
|
+
it "does not set to_key on each parsed header object in the set" do
|
34
|
+
# note: Proc#== bug!
|
35
|
+
to_key = proc { :foo }
|
36
|
+
Redhead::HeaderSet.parse(@full_header_set_string, &to_key).each { |header| header.to_key.should_not == to_key }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it "is Enumerable and responds to #each" do
|
42
|
+
@header_set.is_a?(Enumerable).should be_true
|
43
|
+
@header_set.respond_to?(:each).should be_true
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#[]" do
|
47
|
+
context "for a key with a corresponding header" do
|
48
|
+
it "takes a symbolic header name key and returns a header" do
|
49
|
+
@header_set[:a].is_a?(Redhead::Header).should be_true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "for a key with no corresponding header" do
|
54
|
+
it "returns nil" do
|
55
|
+
@header_set[:something_non_existent].should be_nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "#[]=" do
|
61
|
+
context "for a key with a corresponding header" do
|
62
|
+
it "sets a new header value" do
|
63
|
+
new_value = "new value"
|
64
|
+
@header_set[@first_header_key].should_not be_nil
|
65
|
+
@header_set[@first_header_key] = new_value
|
66
|
+
@header_set[@first_header_key].value.should == new_value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "for a key with no corresponding header" do
|
71
|
+
it "creates a new header with this value" do
|
72
|
+
new_value = "some brand new value"
|
73
|
+
@header_set[:brand_new_key] = new_value
|
74
|
+
@header_set[:brand_new_key].should_not be_nil
|
75
|
+
@header_set[:brand_new_key].value.should == new_value
|
76
|
+
end
|
77
|
+
|
78
|
+
it "calls #to_raw to create the value of #raw" do
|
79
|
+
@header_set.to_raw = proc { "WHOA!" }
|
80
|
+
@header_set[:brand_new_key] = "some value"
|
81
|
+
@header_set[:brand_new_key].raw.should == "WHOA!"
|
82
|
+
end
|
83
|
+
|
84
|
+
it "sets new_header#to_raw to header_set#to_raw" do
|
85
|
+
@header_set.to_raw = proc { "Whoa!" }
|
86
|
+
@header_set[:brand_new_key] = "some value"
|
87
|
+
@header_set[:brand_new_key].to_raw.should == @header_set.to_raw
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "#add" do
|
93
|
+
context "being equivalent to #[]=" do
|
94
|
+
def new_header(header_string)
|
95
|
+
@header_set[:brand_new_key].should be_nil
|
96
|
+
@header_set.add(:brand_new_key, "some value")
|
97
|
+
@header_set[:brand_new_key].should_not be_nil
|
98
|
+
end
|
99
|
+
|
100
|
+
it "parses the given header string, adds the new header to self and returns that header" do
|
101
|
+
new_header(@header_set)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "creates a new header with the given value" do
|
105
|
+
new_header(@header_set)
|
106
|
+
@header_set[:brand_new_key].value.should == "some value"
|
107
|
+
end
|
108
|
+
|
109
|
+
it "returns a Redhead::Header object" do
|
110
|
+
@header_set.add(:brand_new_key, "some value").class.should == Redhead::Header
|
111
|
+
end
|
112
|
+
|
113
|
+
it "calls #to_raw to create the value of #raw" do
|
114
|
+
@header_set.add(:brand_new_key, "some value")
|
115
|
+
@header_set[:brand_new_key].raw.should == "Brand-New-Key"
|
116
|
+
|
117
|
+
@header_set.to_raw = proc { "Nothing really" }
|
118
|
+
@header_set.add(:something_or_other, "something or other")
|
119
|
+
@header_set[:something_or_other].raw.should == "Nothing really"
|
120
|
+
end
|
121
|
+
|
122
|
+
it "sets new_header#to_raw to header_set#to_raw" do
|
123
|
+
@header_set.to_raw = proc { "Whoa!" }
|
124
|
+
@header_set.add(:brand_new_key, "some value")
|
125
|
+
@header_set[:brand_new_key].to_raw.should == @header_set.to_raw
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
it "takes an optional third argument which sets the value of the raw header" do
|
130
|
+
@header_set.add(:foo, "bar", "BAZ!")
|
131
|
+
@header_set[:foo].value.should == "bar"
|
132
|
+
@header_set[:foo].key.should == :foo
|
133
|
+
@header_set[:foo].raw.should == "BAZ!"
|
134
|
+
@header_set[:foo].raw!.should == "Foo"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe "#delete" do
|
139
|
+
it "removes a header from the set" do
|
140
|
+
@header_set[:brand_new_key].should be_nil
|
141
|
+
@header_set[:brand_new_key] = "something random"
|
142
|
+
@header_set[:brand_new_key].should_not be_nil
|
143
|
+
new_header = @header_set[:brand_new_key]
|
144
|
+
@header_set.delete(:brand_new_key)
|
145
|
+
@header_set[:brand_new_key].should be_nil
|
146
|
+
end
|
147
|
+
|
148
|
+
it "returns the deleted header" do
|
149
|
+
@header_set[:brand_new_key] = "test"
|
150
|
+
h = @header_set[:brand_new_key]
|
151
|
+
@header_set.delete(:brand_new_key).should == h
|
152
|
+
end
|
153
|
+
|
154
|
+
it "returns nil if there is no header corresponding to the key" do
|
155
|
+
@header_set[:brand_new_key].should be_nil
|
156
|
+
@header_set.delete(:brand_new_key).should be_nil
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe "#to_s" do
|
161
|
+
it "equals the individual header to_s results, joined with newlines" do
|
162
|
+
@header_set.to_s.should == @headers.map { |header| header.to_s }.join("\n")
|
163
|
+
end
|
164
|
+
|
165
|
+
context %Q{with a hash argument :a => "something raw"} do
|
166
|
+
def modified_full_header_set_string
|
167
|
+
str = "something raw: value_a\n"
|
168
|
+
str += @headers[1..-1].map { |e| "header_#{e.key}: value_#{e.key}" }.join("\n")
|
169
|
+
str
|
170
|
+
end
|
171
|
+
|
172
|
+
it %Q{sets the header with key :a to have #raw == "one" and #value == 1} do
|
173
|
+
str = modified_full_header_set_string
|
174
|
+
|
175
|
+
@header_set.to_s(:a => "something raw").should == str
|
176
|
+
@header_set[:a].raw.should_not == "something raw"
|
177
|
+
@header_set[:a].raw.should == "header_a"
|
178
|
+
end
|
179
|
+
|
180
|
+
it "does not leave a side-effect" do
|
181
|
+
str = modified_full_header_set_string
|
182
|
+
|
183
|
+
@header_set.to_s(:a => "something raw").should == str
|
184
|
+
@header_set[:a].raw.should_not == "something raw"
|
185
|
+
@header_set[:a].raw.should == "header_a"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
context "with a block argument" do
|
190
|
+
def modified_full_header_set_string
|
191
|
+
@headers.map { |e| "#{yield e.key}: value_#{e.key}" }.join("\n")
|
192
|
+
end
|
193
|
+
|
194
|
+
it "uses the given block to convert #key to a raw header, for each header in the set" do
|
195
|
+
@header_set.to_s { "testing" + "testing" }.should == modified_full_header_set_string { "testing" + "testing" }
|
196
|
+
|
197
|
+
new_to_raw = proc { |x| x.to_s.upcase.reverse }
|
198
|
+
|
199
|
+
@header_set.to_s(&new_to_raw).should == modified_full_header_set_string(&new_to_raw)
|
200
|
+
end
|
201
|
+
|
202
|
+
it "does not leave the given block as #to_raw" do
|
203
|
+
@header_set.to_s { "test" + "test" }
|
204
|
+
@header_set.to_raw.should_not == proc { "test" + "test" }
|
205
|
+
end
|
206
|
+
|
207
|
+
it "follows the hash argument first, falling back to the given block" do
|
208
|
+
@header_set.to_s(:a => "something raw") { "NOT RAW AT ALL" }.split("\n").first.should == "something raw: value_a"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
describe "#to_s!" do
|
214
|
+
context "without a block" do
|
215
|
+
it "calls to_s! on each header in the set, passing #to_raw as a block joining the results with newlines" do
|
216
|
+
@header_set.to_raw = proc { "Total foo bar" }
|
217
|
+
@header_set.to_s!.should == @headers.map { |header| "Total foo bar: #{header.value}" }.join("\n")
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
context "with a block" do
|
222
|
+
it "calls to_s! on each header in the set, passing the given block, joining the results with newlines" do
|
223
|
+
@header_set.to_s! { "Total foo bar" }.should == @headers.map { |header| "Total foo bar: #{header.value}" }.join("\n")
|
224
|
+
end
|
225
|
+
|
226
|
+
it "does not leave the given block as #to_raw on existing headers" do
|
227
|
+
temp_to_raw = proc { "Total foo bar" }
|
228
|
+
@header_set.to_s!(&temp_to_raw)
|
229
|
+
@header_set.all? { |header| header.raw!.should_not == "Total foo bar" }
|
230
|
+
end
|
231
|
+
|
232
|
+
it "does not leave the given block as #to_raw on the header set" do
|
233
|
+
temp_to_raw = proc { "Total foo bar" }
|
234
|
+
@header_set.to_s!(&temp_to_raw)
|
235
|
+
@header_set.to_raw.should_not == temp_to_raw
|
236
|
+
@header_set[:temp_foo_foo] = "what"
|
237
|
+
@header_set[:temp_foo_foo].raw!.should_not == "Total foo bar"
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
describe "#==(other_header)" do
|
243
|
+
it "is sane." do
|
244
|
+
@header_set.should == @header_set
|
245
|
+
|
246
|
+
Redhead::HeaderSet.parse("Test: test").should == Redhead::HeaderSet.parse("Test: test")
|
247
|
+
end
|
248
|
+
|
249
|
+
it "returns true if, for every header in self, there is a corresponding header in other_header equal to it, using Header#==" do
|
250
|
+
one, two = @header_set.partition { |header| header.key.to_s < @header_set.to_a[1].key.to_s }.map { |part| Redhead::HeaderSet.new(part) }
|
251
|
+
|
252
|
+
one.all? { |a| two.find { |b| a == b } }.should be_false
|
253
|
+
# sanity check with any?
|
254
|
+
one.any? { |a| two.find { |b| a == b } }.should be_false
|
255
|
+
|
256
|
+
one << two.first # create an overlap
|
257
|
+
|
258
|
+
one.all? { |a| two.find { |b| a == b } }.should be_false
|
259
|
+
# sanity check with any?
|
260
|
+
one.any? { |a| two.find { |b| a == b } }.should be_true
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
describe "#reversible?" do
|
265
|
+
it "returns true if each header in the set is reversible, otherwise false" do
|
266
|
+
@reversible_headers.reversible?.should == @reversible_headers.all? { |header| header.reversible? }
|
267
|
+
@irreversible_headers.reversible?.should == @irreversible_headers.all? { |header| header.reversible? }
|
268
|
+
|
269
|
+
@reversible_headers.reversible?.should be_true
|
270
|
+
@irreversible_headers.reversible?.should be_false
|
271
|
+
|
272
|
+
@reversible_headers.to_raw = proc { "" }
|
273
|
+
@reversible_headers.reversible?.should_not be_true # contained headers get caught up in the change
|
274
|
+
|
275
|
+
# example from the readme:
|
276
|
+
|
277
|
+
string = "A-Header-Name: a header value\n\nContent."
|
278
|
+
|
279
|
+
str = Redhead::String.new(string) do |name|
|
280
|
+
name.gsub(/-/, "").upcase.to_sym
|
281
|
+
end
|
282
|
+
|
283
|
+
str.headers.reversible?.should be_false
|
284
|
+
|
285
|
+
str = Redhead::String.new(string) do |name|
|
286
|
+
name.split(/-/).map { |e| e.upcase }.join("zzz").to_sym
|
287
|
+
end
|
288
|
+
|
289
|
+
str.headers.reversible?.should be_false
|
290
|
+
|
291
|
+
str.headers.to_raw = lambda do |name|
|
292
|
+
name.to_s.split(/zzz/).map { |e| e.capitalize }.join("-")
|
293
|
+
end
|
294
|
+
|
295
|
+
str.headers.reversible?.should be_true
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
describe "#to_raw" do
|
300
|
+
it "defaults to Redhead.to_raw" do
|
301
|
+
# note: Proc#== bug!
|
302
|
+
@header_set.to_raw.should == @default_to_raw
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
describe "#to_raw=" do
|
307
|
+
it "sets a new block to be used as to_raw" do
|
308
|
+
# note: Proc#== bug!
|
309
|
+
new_to_raw = proc { "" + "" }
|
310
|
+
@header_set.to_raw = new_to_raw
|
311
|
+
@header_set.to_raw.should_not == @default_to_raw
|
312
|
+
@header_set.to_raw.should == new_to_raw
|
313
|
+
end
|
314
|
+
|
315
|
+
it "sets to_raw, for each header in the set" do
|
316
|
+
new_to_raw = proc { "" + "" }
|
317
|
+
@header_set.to_raw = new_to_raw
|
318
|
+
@header_set.each { |header| header.to_raw.should == new_to_raw }
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
describe "#to_key" do
|
323
|
+
it "defaults to Redhead.to_key" do
|
324
|
+
# note: Proc#== bug!
|
325
|
+
@header_set.to_key.should == @default_to_key
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
describe "#to_key=" do
|
330
|
+
it "sets a new block to be used as to_key" do
|
331
|
+
# note: Proc#== bug!
|
332
|
+
new_to_key = proc { "" + "" }
|
333
|
+
@header_set.to_key = new_to_key
|
334
|
+
@header_set.to_key.should_not == @default_to_key
|
335
|
+
@header_set.to_key.should == new_to_key
|
336
|
+
end
|
337
|
+
|
338
|
+
it "sets to_key, for each header in the set" do
|
339
|
+
new_to_key = proc { "" + "" }
|
340
|
+
@header_set.to_key = new_to_key
|
341
|
+
@header_set.each { |header| header.to_key.should == new_to_key }
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|