1+ module OneLogin
2+ module RubySaml
3+ # Wraps all attributes and provides means to query them for single or multiple values.
4+ #
5+ # For backwards compatibility Attributes#[] returns *first* value for the attribute.
6+ # Turn off compatibility to make it return all values as an array:
7+ # Attributes.single_value_compatibility = false
8+ class Attributes
9+ include Enumerable
10+
11+ # By default Attributes#[] is backwards compatible and
12+ # returns only the first value for the attribute
13+ # Setting this to `false` returns all values for an attribute
14+ @@single_value_compatibility = true
15+
16+ # Get current status of backwards compatibility mode.
17+ def self . single_value_compatibility
18+ @@single_value_compatibility
19+ end
20+
21+ # Sets the backwards compatibility mode on/off.
22+ def self . single_value_compatibility = ( value )
23+ @@single_value_compatibility = value
24+ end
25+
26+ # Initialize Attributes collection, optionally taking a Hash of attribute names and values.
27+ #
28+ # The +attrs+ must be a Hash with attribute names as keys and **arrays** as values:
29+ # Attributes.new({
30+ # 'name' => ['value1', 'value2'],
31+ # 'mail' => ['value1'],
32+ # })
33+ def initialize ( attrs = { } )
34+ @attributes = attrs
35+ end
36+
37+
38+ # Iterate over all attributes
39+ def each
40+ attributes . each { |name , values | yield name , values }
41+ end
42+
43+ # Test attribute presence by name
44+ def include? ( name )
45+ attributes . has_key? ( canonize_name ( name ) )
46+ end
47+
48+ # Return first value for an attribute
49+ def single ( name )
50+ attributes [ canonize_name ( name ) ] . first
51+ end
52+
53+ # Return all values for an attribute
54+ def multi ( name )
55+ attributes [ canonize_name ( name ) ]
56+ end
57+
58+ # By default returns first value for an attribute.
59+ #
60+ # Depending on the single value compatibility status this returns first value
61+ # Attributes.single_value_compatibility = true # Default
62+ # response.attributes['mail'] # => 'user@example.com'
63+ #
64+ # Or all values:
65+ # Attributes.single_value_compatibility = false
66+ # response.attributes['mail'] # => ['user@example.com','user@example.net']
67+ def []( name )
68+ self . class . single_value_compatibility ? single ( canonize_name ( name ) ) : multi ( canonize_name ( name ) )
69+ end
70+
71+ # Return all attributes as an array
72+ def all
73+ attributes
74+ end
75+
76+ # Set values for an attribute, overwriting all existing values
77+ def set ( name , values )
78+ attributes [ canonize_name ( name ) ] = values
79+ end
80+ alias_method :[]= , :set
81+
82+ # Add new attribute or new value(s) to an existing attribute
83+ def add ( name , values = [ ] )
84+ attributes [ canonize_name ( name ) ] ||= [ ]
85+ attributes [ canonize_name ( name ) ] += Array ( values )
86+ end
87+
88+ # Make comparable to another Attributes collection based on attributes
89+ def ==( other )
90+ if other . is_a? ( Attributes )
91+ all == other . all
92+ else
93+ super
94+ end
95+ end
96+
97+ protected
98+
99+ # stringifies all names so both 'email' and :email return the same result
100+ def canonize_name ( name )
101+ name . to_s
102+ end
103+
104+ def attributes
105+ @attributes
106+ end
107+ end
108+ end
109+ end
0 commit comments