ALD 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/ALD/api.rb +285 -0
- data/lib/ALD/collection.rb +96 -0
- data/lib/ALD/collection_entry.rb +77 -0
- data/lib/ALD/conditioned.rb +216 -0
- data/lib/ALD/item.rb +186 -0
- data/lib/ALD/item_collection.rb +169 -0
- data/lib/ALD/local_filter.rb +136 -0
- data/lib/ALD/user.rb +94 -0
- data/lib/ALD/user_collection.rb +140 -0
- metadata +12 -4
- data/lib/ALD/schema.xsd +0 -340
@@ -0,0 +1,216 @@
|
|
1
|
+
require 'semantic'
|
2
|
+
|
3
|
+
module ALD
|
4
|
+
class API
|
5
|
+
# Internal: used by Collection classes to work with special conditions in #where.
|
6
|
+
#
|
7
|
+
# Requires @conditions to be the instance's condition Hash.
|
8
|
+
module Conditioned
|
9
|
+
# Public: Filter the Collection's data.
|
10
|
+
# See the documentation on the individual classes for more information.
|
11
|
+
def where(conditions)
|
12
|
+
return self if conditions.nil? || conditions.empty?
|
13
|
+
new_conditions = merge_conditions(conditions)
|
14
|
+
|
15
|
+
if initialized? && Collection::LocalFilter.can_apply?(conditions, self.class::LOCAL_CONDITIONS)
|
16
|
+
self.class::new(
|
17
|
+
@api,
|
18
|
+
new_conditions,
|
19
|
+
Collection::LocalFilter.apply_conditions(@data, conditions)
|
20
|
+
)
|
21
|
+
else
|
22
|
+
self.class::new(@api, new_conditions)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Internal: The HTTP query conditions for the range specified in the
|
29
|
+
# instance's conditions.
|
30
|
+
#
|
31
|
+
# Returns a Hash, that contains the query parameters matching the range
|
32
|
+
# specified in the conditions, or an empty Hash if there is no range
|
33
|
+
# specified.
|
34
|
+
def range_query
|
35
|
+
data = {}
|
36
|
+
if @conditions.key?(:range)
|
37
|
+
data['start'] = @conditions[:range].min
|
38
|
+
data['count'] = @conditions[:range].max - @conditions[:range].min + 1
|
39
|
+
end
|
40
|
+
data
|
41
|
+
end
|
42
|
+
|
43
|
+
# Internal: The HTTP query conditions for the sorting specified in the
|
44
|
+
# instance's conditions.
|
45
|
+
#
|
46
|
+
# Returns a Hash containing the query parameters matching the specified
|
47
|
+
# sorting, or an empty Hash if there's no sorting specified.
|
48
|
+
def sort_query
|
49
|
+
Hash[
|
50
|
+
present_conditions(%w[sort]).map { |cond| [cond, @conditions[cond.to_sym].map { |k, dir| "#{dir == :desc ? '-' : ''}#{k}" }.join(',')] }
|
51
|
+
]
|
52
|
+
end
|
53
|
+
|
54
|
+
# Internal: The HTTP query conditions for exact queries for a set of
|
55
|
+
# given conditions.
|
56
|
+
#
|
57
|
+
# conds - an Array of Strings, containing the condition names to handle
|
58
|
+
#
|
59
|
+
# Returns a Hash with the query parameters matching the instance's values
|
60
|
+
# on the specified conditions, or an empty Hash, if there are none.
|
61
|
+
def exact_queries(conds)
|
62
|
+
Hash[
|
63
|
+
present_conditions(conds).map { |cond| [cond, @conditions[cond.to_sym]] }
|
64
|
+
]
|
65
|
+
end
|
66
|
+
|
67
|
+
# Internal: The HTTP query conditions for queries for an array of values
|
68
|
+
# for the given conditions.
|
69
|
+
#
|
70
|
+
# conds - an Array of Strings, containing the condition names to handle
|
71
|
+
#
|
72
|
+
# Returns a Hash with the query parameters matching the instance's values
|
73
|
+
# on the specified conditions, or an empty Hash.
|
74
|
+
def array_queries(conds)
|
75
|
+
Hash[
|
76
|
+
present_conditions(conds).map { |cond| [cond, @conditions[cond.to_sym].join(',')] }
|
77
|
+
]
|
78
|
+
end
|
79
|
+
|
80
|
+
# Internal: The HTTP query conditions for queries with conditions that
|
81
|
+
# can be switched on, off or indeterminate.
|
82
|
+
#
|
83
|
+
# conds - an Array of Strings, containing the condition names to handle
|
84
|
+
#
|
85
|
+
# Returns a Hash with the query parameters matching the instance's values
|
86
|
+
# on the specified conditions, or an empty Hash.
|
87
|
+
def switch_queries(conds)
|
88
|
+
map = {true => 'true', false => 'false', nil => 'both'}
|
89
|
+
Hash[
|
90
|
+
present_conditions(conds).map { |cond| [cond, map[@conditions[cond.to_sym]]] }
|
91
|
+
]
|
92
|
+
end
|
93
|
+
|
94
|
+
# Internal: The HTTP query conditions for queries with conditions that
|
95
|
+
# allow specifying a range of values.
|
96
|
+
#
|
97
|
+
# conds - an Array of Strings, containing the condition names to handle
|
98
|
+
#
|
99
|
+
# Returns a Hash with the query parameters matching the instance's values
|
100
|
+
# on the specified conditions, or an empty Hash.
|
101
|
+
def range_condition_queries(conds)
|
102
|
+
Hash[
|
103
|
+
present_conditions(conds).map { |cond|
|
104
|
+
fields = @conditions[cond.to_sym].is_a?(Array) ? @conditions[cond.to_sym] : [@conditions[cond.to_sym]]
|
105
|
+
fields.map do |field|
|
106
|
+
match = RANGE_REGEX.match(field)
|
107
|
+
if match.nil? # just a specific field
|
108
|
+
[cond, field]
|
109
|
+
else # min or max
|
110
|
+
["#{cond}-#{match[1] == '>=' ? 'min' : 'max'}", match[2]]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
}.flatten(1)
|
114
|
+
]
|
115
|
+
end
|
116
|
+
|
117
|
+
# Internal: Get the subset of conditions that are present on the instance
|
118
|
+
#
|
119
|
+
# conds - an Array of Strings, containing the condition names to check
|
120
|
+
#
|
121
|
+
# Returns an Array of Strings with a subset of the given conds, namely
|
122
|
+
# those that are present on @conditions.
|
123
|
+
def present_conditions(conds)
|
124
|
+
conds.select { |cond| @conditions.key?(cond.to_sym) }
|
125
|
+
end
|
126
|
+
|
127
|
+
# Internal: Merge new conditions with the current ones.
|
128
|
+
#
|
129
|
+
# conditions - the new condition Hash to merge
|
130
|
+
#
|
131
|
+
# Returns the merged Hash
|
132
|
+
#
|
133
|
+
# Raises ArgumentError if the conditions are incompatible
|
134
|
+
def merge_conditions(conditions)
|
135
|
+
@conditions.merge(conditions) do |key, old_value, new_value|
|
136
|
+
if self.class::RANGE_CONDITIONS.include?(key.to_s)
|
137
|
+
merge_ranges(key, old_value, new_value) # handle merging for cases like 'downloads >= 5' and 'downloads <= 9' etc.
|
138
|
+
elsif self.class::ARRAY_CONDITIONS.include?(key.to_s)
|
139
|
+
old_value + new_value
|
140
|
+
elsif key == :range # not a "range condition" in the sense used above
|
141
|
+
range_offset(new_value)
|
142
|
+
elsif key == :sort
|
143
|
+
new_value # enable re-sorting
|
144
|
+
else
|
145
|
+
raise ArgumentError # for other overwrites fail!
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Internal: A regex to determine if a range condition is specifying a range.
|
151
|
+
RANGE_REGEX = /^\s*(<\=|>\=)\s*(.*)$/
|
152
|
+
|
153
|
+
# Internal: Handle condition conflicts for range conditions. Used by #where.
|
154
|
+
#
|
155
|
+
# key - the Symbol key whose range is merged
|
156
|
+
# old - the old range condition value
|
157
|
+
# new - the new range condition value to be applied on top of the old one
|
158
|
+
#
|
159
|
+
# Returns the value that should be used in the merged conditions.
|
160
|
+
#
|
161
|
+
# Raises ArgumentError if the conflict cannot be resolved.
|
162
|
+
def merge_ranges(key, old, new)
|
163
|
+
constraints = [new, old]
|
164
|
+
data = constraints.map do |c|
|
165
|
+
match = RANGE_REGEX.match(c)
|
166
|
+
if match.nil?
|
167
|
+
[nil, c]
|
168
|
+
elsif key == :version
|
169
|
+
[match[1], Semantic::Version.new(match[2])]
|
170
|
+
else
|
171
|
+
[match[1], match[2]]
|
172
|
+
end
|
173
|
+
end
|
174
|
+
ops, values = data.map(&:first), data.map(&:last)
|
175
|
+
|
176
|
+
if ops[0] != ops[1] # one min, one max OR one min/max, one exact
|
177
|
+
constraints # => keep both
|
178
|
+
|
179
|
+
elsif ops.none?(&:'nil?') # two range constraints of same type
|
180
|
+
ops[0] == '>=' ? ">= #{values.max.to_s}" : "<= #{values.min.to_s}"
|
181
|
+
|
182
|
+
else # two exact values
|
183
|
+
if constraints[0].strip == constraints[1].strip # if both are the same, just keep one
|
184
|
+
constraints[0]
|
185
|
+
else # otherwise this can't be good - throw an error
|
186
|
+
raise ArgumentError
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Internal: Compute an absolute Range from a given relative Range. As
|
192
|
+
# ranges specified in #where are relative to this collection, they must
|
193
|
+
# be transformed to absolute ranges before being passed to ::new.
|
194
|
+
#
|
195
|
+
# new_range - the relative Range to transform
|
196
|
+
#
|
197
|
+
# Returns the absolute Range.
|
198
|
+
#
|
199
|
+
# Raises ArgumentError if the relative Range does not fit into this
|
200
|
+
# collection's Range.
|
201
|
+
def range_offset(new_range)
|
202
|
+
if @conditions[:range].nil?
|
203
|
+
min, max = 0, Float::Infinity
|
204
|
+
else
|
205
|
+
min, max = @conditions[:range].min, @conditions[:range].max
|
206
|
+
end
|
207
|
+
|
208
|
+
new_min = min + new_range.min
|
209
|
+
new_max = new_min + new_range.max - new_range.min # == new_min + new_range.size - 1
|
210
|
+
raise ArgumentError if new_min > max || new_max > max
|
211
|
+
|
212
|
+
(new_min..new_max)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
data/lib/ALD/item.rb
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
require_relative 'collection_entry'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
module ALD
|
5
|
+
class API
|
6
|
+
# Public: An item (e.g. a library or app) uploaded to an ALD server.
|
7
|
+
class Item < CollectionEntry
|
8
|
+
|
9
|
+
# Public: Get the ID of the item.
|
10
|
+
#
|
11
|
+
# Examples
|
12
|
+
#
|
13
|
+
# puts item.id
|
14
|
+
#
|
15
|
+
# Returns a String of 32 characters, containing the item's GUID.
|
16
|
+
#
|
17
|
+
# Signature
|
18
|
+
#
|
19
|
+
# item()
|
20
|
+
|
21
|
+
# Public: Get the name of the item.
|
22
|
+
#
|
23
|
+
# Examples
|
24
|
+
#
|
25
|
+
# puts "Item: #{item.name}"
|
26
|
+
#
|
27
|
+
# Returns a String containing the item name.
|
28
|
+
#
|
29
|
+
# Signature
|
30
|
+
#
|
31
|
+
# name()
|
32
|
+
|
33
|
+
# Public: Get the item version.
|
34
|
+
#
|
35
|
+
# Examples
|
36
|
+
#
|
37
|
+
# puts "#{item.name} v#{item.version}"
|
38
|
+
#
|
39
|
+
# Returns a String containing the version of the item.
|
40
|
+
#
|
41
|
+
# Signature
|
42
|
+
#
|
43
|
+
# version()
|
44
|
+
|
45
|
+
# Public: Get the item's summary text. This method might trigger a HTTP
|
46
|
+
# request.
|
47
|
+
#
|
48
|
+
# Returns a String summarizing the item's purpose and contents.
|
49
|
+
#
|
50
|
+
# Signature
|
51
|
+
#
|
52
|
+
# summary()
|
53
|
+
|
54
|
+
# Public: Get the item's description text. This method might trigger a
|
55
|
+
# HTTP request.
|
56
|
+
#
|
57
|
+
# Returns a String with the item's description.
|
58
|
+
#
|
59
|
+
# Signature
|
60
|
+
#
|
61
|
+
# description()
|
62
|
+
|
63
|
+
# Public: Get the time the item was uploaded. This method might trigger a
|
64
|
+
# HTTP request.
|
65
|
+
#
|
66
|
+
# Returns a DateTime describing the time the item was first uploaded to
|
67
|
+
# the ALD server.
|
68
|
+
#
|
69
|
+
# Signature
|
70
|
+
#
|
71
|
+
# uploaded()
|
72
|
+
|
73
|
+
# Public: Get if the item has been marked as reviewed by the ALD server.
|
74
|
+
# This method might trigger a HTTP request.
|
75
|
+
#
|
76
|
+
# Returns a Boolean indicating if the item was revieed or not.
|
77
|
+
#
|
78
|
+
# Signature
|
79
|
+
#
|
80
|
+
# reviewed()
|
81
|
+
|
82
|
+
# Public: Get the number of downloads for the item. This method might
|
83
|
+
# trigger a HTTP request.
|
84
|
+
#
|
85
|
+
# Returns an Integer indicating how often the item was downloaded.
|
86
|
+
#
|
87
|
+
# Signature
|
88
|
+
#
|
89
|
+
# downloads()
|
90
|
+
|
91
|
+
# Public: Get the tags the item was tagged with. This method might
|
92
|
+
# trigger a HTTP request.
|
93
|
+
#
|
94
|
+
# Returns an Array of Symbols representing the tags.
|
95
|
+
#
|
96
|
+
# Signature
|
97
|
+
#
|
98
|
+
# tags()
|
99
|
+
|
100
|
+
# Public: get author information from the item. This method might trigger
|
101
|
+
# a HTTP request.
|
102
|
+
#
|
103
|
+
# Returns an Array of Hashes describing the authors.
|
104
|
+
#
|
105
|
+
# Signature
|
106
|
+
#
|
107
|
+
# authors()
|
108
|
+
|
109
|
+
# Public: Get the user who owns the item. This method might trigger a
|
110
|
+
# HTTP request.
|
111
|
+
#
|
112
|
+
# Returns the ALD::API::User who owns the item.
|
113
|
+
#
|
114
|
+
# Signature
|
115
|
+
#
|
116
|
+
# user()
|
117
|
+
|
118
|
+
# Public: Get the ratings the item was given. This method might trigger a
|
119
|
+
# HTTP request.
|
120
|
+
#
|
121
|
+
# Returns an Array of Integers representing the ratings given to the item
|
122
|
+
# by users.
|
123
|
+
#
|
124
|
+
# Signature
|
125
|
+
#
|
126
|
+
# ratings()
|
127
|
+
|
128
|
+
# Internal: Create a new instance for given data. This method should not
|
129
|
+
# called by library consumers. Instead access entries via API#item or
|
130
|
+
# ItemCollection#[].
|
131
|
+
#
|
132
|
+
# api - the ALD::API instance this item belongs to
|
133
|
+
# data - a Hash containing data concerning the item:
|
134
|
+
# id - the GUID of the item
|
135
|
+
# name - the name of the item
|
136
|
+
# version - the semver version of the item
|
137
|
+
# The above fields are mandatory. However, the hash may
|
138
|
+
# contain a lot more data about the item.
|
139
|
+
# initialized - a Boolean indicating if data only contains the mandatory
|
140
|
+
# fields or *all* data on the item.
|
141
|
+
def initialize(api, data, initialized = false)
|
142
|
+
raise ArgumentError unless Item.valid_data?(data)
|
143
|
+
super(api, data, initialized)
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
|
148
|
+
# Internal: If the item was initialized with only mandatory data, use the
|
149
|
+
# API to request all missing information.
|
150
|
+
#
|
151
|
+
# Returns nothing.
|
152
|
+
def request
|
153
|
+
@data = @api.request("/items/#{id}")
|
154
|
+
@data['uploaded'] = DateTime.parse(@data['uploaded'])
|
155
|
+
@data['tags'].map!(&:to_sym)
|
156
|
+
@data['user'] = @api.user(@data['user'])
|
157
|
+
end
|
158
|
+
|
159
|
+
# Internal: Ensure a Hash contains all information necessary to be passed
|
160
|
+
# to #new.
|
161
|
+
#
|
162
|
+
# data - the Hash to check for mandatory fields
|
163
|
+
#
|
164
|
+
# Returns true if the Hash is valid, false otherwise.
|
165
|
+
def self.valid_data?(data)
|
166
|
+
data.is_a?(Hash) && initialized_attributes.all? { |k| data.key?(k) }
|
167
|
+
end
|
168
|
+
|
169
|
+
# Internal: Override of CollectionEntry#initialized_attributes to enable
|
170
|
+
# automatic method definition, in this case #id, #name and #version.
|
171
|
+
#
|
172
|
+
# Returns an Array of attribute names (String)
|
173
|
+
def self.initialized_attributes
|
174
|
+
%w[id name version]
|
175
|
+
end
|
176
|
+
|
177
|
+
# Internal: Override of CollectionEntry#requested_attributes to enable
|
178
|
+
# automatic method definition.
|
179
|
+
#
|
180
|
+
# Returns an Array of attribute names (String)
|
181
|
+
def self.requested_attributes
|
182
|
+
%w[summary description uploaded reviewed downloads tags authors user ratings]
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require_relative 'collection'
|
2
|
+
require_relative 'conditioned'
|
3
|
+
require_relative 'local_filter'
|
4
|
+
|
5
|
+
module ALD
|
6
|
+
class API
|
7
|
+
# Public: Represents a (possibly filtered) set of items on an ALD server
|
8
|
+
class ItemCollection < Collection
|
9
|
+
include Conditioned
|
10
|
+
|
11
|
+
# Internal: Create a new instance. This should not be called by library
|
12
|
+
# consumers. Instead use API#items or #where to get a new instance.
|
13
|
+
#
|
14
|
+
# api - the ALD::API instance this collection belongs to
|
15
|
+
# conditions - a Hash of conditions items in this collection must meet
|
16
|
+
# data - an Array of Hashes representing the items in this
|
17
|
+
# collection:
|
18
|
+
# id - the GUID of the item
|
19
|
+
# name - the item's name
|
20
|
+
# version - the item's semver version
|
21
|
+
def initialize(api, conditions = {}, data = nil)
|
22
|
+
super(api, conditions, data)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Public: Access an individual item by ID, name and version or index in
|
26
|
+
# the collection. This method may trigger a HTTP request.
|
27
|
+
#
|
28
|
+
# Examples
|
29
|
+
#
|
30
|
+
# items['185d265f24654545aad3f88e8a383339'] # access the item with this ID
|
31
|
+
# items['MyApp', '0.1.2'] # access a specific version of an item
|
32
|
+
# items[4] # access the 5th item in the collection (zero-based index)
|
33
|
+
# # This makes most sense in an explicitly ordered collection
|
34
|
+
#
|
35
|
+
# Returns the corresponding ALD::API::Item instance, or nil if not found
|
36
|
+
#
|
37
|
+
# Signature
|
38
|
+
#
|
39
|
+
# [](id)
|
40
|
+
# [](name, version)
|
41
|
+
# [](index)
|
42
|
+
#
|
43
|
+
# id - a GUID String uniquely identifying the item
|
44
|
+
# name - a String containing the item's name
|
45
|
+
# version - a String containing the item's semver version
|
46
|
+
# index - an Integer with the item's zero-based index within the
|
47
|
+
# collection.
|
48
|
+
|
49
|
+
# Internal: filter conditions that allow specifying a range, like
|
50
|
+
# 'version-min=0.2.1&version-max=3.4.5'
|
51
|
+
RANGE_CONDITIONS = %w[version downloads rating]
|
52
|
+
|
53
|
+
# Internal: filter conditions that allow specifying an array.
|
54
|
+
ARRAY_CONDITIONS = %w[tags]
|
55
|
+
|
56
|
+
# Internal: filter conditions that can be handled locally.
|
57
|
+
LOCAL_CONDITIONS = %w[name version]
|
58
|
+
|
59
|
+
# Public: Filter and/or sort this collection and return a new collection
|
60
|
+
# containing a subset of its items.
|
61
|
+
#
|
62
|
+
# conditions - a Hash of conditions to filter for
|
63
|
+
# :name - filter for items with this name (String)
|
64
|
+
# :user - only return items by this user (given the user
|
65
|
+
# name or the ID) (String)
|
66
|
+
# :type - only return items of this type (String)
|
67
|
+
# :downloads - If given only a number, return only items with
|
68
|
+
# this number of downloads. More commonly, pass
|
69
|
+
# a string like '>= 4' or '<= 5' (or an array of
|
70
|
+
# such strings) to select items in a range of
|
71
|
+
# download counts.
|
72
|
+
# :rating - Select items with a given rating. Like
|
73
|
+
# for :downloads, ranges can be specified.
|
74
|
+
# :version - Only items with a given semver version number.
|
75
|
+
# Here as well, ranges can be specified. Semver
|
76
|
+
# rules are taken into account when sorting.
|
77
|
+
# :stable - Set to true to only return items whose semver
|
78
|
+
# version indicates they're stable.
|
79
|
+
# :reviewed - Set to true to filter for items that are marked
|
80
|
+
# as reviewed by the server.
|
81
|
+
# :tags - A tag or an array of tags to filter for.
|
82
|
+
# :sort - an Array of sorting criteria, in descending
|
83
|
+
# order of precedence; or a Hash where the keys
|
84
|
+
# are the sorting criteria, and the values (:asc,
|
85
|
+
# :desc) indicate sorting order.
|
86
|
+
# :range - A zero-based Range of items to return. This
|
87
|
+
# makes most sense in combination with sorting.
|
88
|
+
# Note that the range is relative to the
|
89
|
+
# collection the operation is performed upon.
|
90
|
+
#
|
91
|
+
# Returns a new ItemCollection instance (or self, if conditions is nil)
|
92
|
+
#
|
93
|
+
# Raises ArgumentError if the conditions are invalid or incompatible with
|
94
|
+
# this collection's conditions.
|
95
|
+
#
|
96
|
+
# Signature
|
97
|
+
#
|
98
|
+
# where(conditions)
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
# Internal: Make a HTTP request to the ALD server to get the list of item
|
103
|
+
# hashes matching this collection's conditions.
|
104
|
+
#
|
105
|
+
# Returns nothing.
|
106
|
+
def request
|
107
|
+
data = [
|
108
|
+
exact_queries(%w[name user type]),
|
109
|
+
switch_queries(%w[stable reviewed]),
|
110
|
+
array_queries(%w[tags]),
|
111
|
+
range_condition_queries(%w[downloads rating version]),
|
112
|
+
sort_query,
|
113
|
+
range_query
|
114
|
+
].reduce({}, :merge)
|
115
|
+
|
116
|
+
url = "/items/#{data.empty? ? '' : '?'}#{URI.encode_www_form(data)}"
|
117
|
+
@data = @api.request(url).map do |hash|
|
118
|
+
hash['id'] = @api.normalize_id(hash['id'])
|
119
|
+
hash
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Internal: Make a HTTP request to the ALD server to get a single item.
|
124
|
+
# Used by Collection#[].
|
125
|
+
#
|
126
|
+
# filter - a filter Hash as returned by #entry_filter
|
127
|
+
#
|
128
|
+
# Returns a Hash with all information about the item.
|
129
|
+
#
|
130
|
+
# Raises ArgumentError if the filters cannot be handled.
|
131
|
+
def request_entry(filter)
|
132
|
+
url = if filter.key?(:id)
|
133
|
+
"/items/#{filter[:id]}"
|
134
|
+
elsif %w[name version].all? { |k| filter.key?(k.to_sym) }
|
135
|
+
"/items/#{filter[:name]}/#{filter[:version]}"
|
136
|
+
else
|
137
|
+
raise ArgumentError
|
138
|
+
end
|
139
|
+
|
140
|
+
@api.request(url)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Internal: Used by Collection#each and Collection#[] to create new items.
|
144
|
+
#
|
145
|
+
# hash - a Hash describing the item, with the keys 'id', 'name'
|
146
|
+
# and 'version'.
|
147
|
+
# initialized - a Boolean indicating if the given Hash already contains
|
148
|
+
# all information about the item or only name and id.
|
149
|
+
def entry(hash, initialized = false)
|
150
|
+
@api.item(hash, initialized)
|
151
|
+
end
|
152
|
+
|
153
|
+
# Internal: Implements item access for #[]. See Collection#entry_filter
|
154
|
+
# for more information.
|
155
|
+
#
|
156
|
+
# ItemCollection allows access by ID (String) or name and version
|
157
|
+
# (both String).
|
158
|
+
def entry_filter(args)
|
159
|
+
if args.length == 1 && args.first.is_a?(String)
|
160
|
+
{ id: @api.normalize_id(args.first) }
|
161
|
+
elsif args.length == 2
|
162
|
+
{ name: args.first, version: args.last }
|
163
|
+
else
|
164
|
+
raise ArgumentError
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|