supplejack_client 1.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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +27 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +16 -0
  5. data/Guardfile +24 -0
  6. data/LICENSE.txt +674 -0
  7. data/README.md +153 -0
  8. data/Rakefile +9 -0
  9. data/lib/generators/locales/en.yml +11 -0
  10. data/lib/generators/supplejack/install_generator.rb +28 -0
  11. data/lib/generators/templates/README +19 -0
  12. data/lib/generators/templates/supplejack_client.rb +120 -0
  13. data/lib/supplejack/config.rb +116 -0
  14. data/lib/supplejack/controllers/helpers.rb +172 -0
  15. data/lib/supplejack/engine.rb +20 -0
  16. data/lib/supplejack/exceptions.rb +17 -0
  17. data/lib/supplejack/facet.rb +33 -0
  18. data/lib/supplejack/item.rb +94 -0
  19. data/lib/supplejack/item_relation.rb +73 -0
  20. data/lib/supplejack/log_subscriber.rb +58 -0
  21. data/lib/supplejack/paginated_collection.rb +61 -0
  22. data/lib/supplejack/record.rb +147 -0
  23. data/lib/supplejack/request.rb +95 -0
  24. data/lib/supplejack/search.rb +346 -0
  25. data/lib/supplejack/url_formats/item_hash.rb +208 -0
  26. data/lib/supplejack/user.rb +132 -0
  27. data/lib/supplejack/user_set.rb +349 -0
  28. data/lib/supplejack/user_set_relation.rb +143 -0
  29. data/lib/supplejack/util.rb +120 -0
  30. data/lib/supplejack/version.rb +10 -0
  31. data/lib/supplejack_client.rb +29 -0
  32. data/spec/spec_helper.rb +23 -0
  33. data/spec/supplejack/controllers/helpers_spec.rb +277 -0
  34. data/spec/supplejack/facet_spec.rb +44 -0
  35. data/spec/supplejack/item_relation_spec.rb +111 -0
  36. data/spec/supplejack/item_spec.rb +115 -0
  37. data/spec/supplejack/log_subscriber_spec.rb +40 -0
  38. data/spec/supplejack/paginated_collection_spec.rb +43 -0
  39. data/spec/supplejack/record_spec.rb +255 -0
  40. data/spec/supplejack/request_spec.rb +195 -0
  41. data/spec/supplejack/search_spec.rb +727 -0
  42. data/spec/supplejack/url_formats/item_hash_spec.rb +341 -0
  43. data/spec/supplejack/user_set_relation_spec.rb +149 -0
  44. data/spec/supplejack/user_set_spec.rb +465 -0
  45. data/spec/supplejack/user_spec.rb +159 -0
  46. data/supplejack_client.gemspec +30 -0
  47. metadata +159 -0
@@ -0,0 +1,143 @@
1
+ # The Supplejack Client code is Crown copyright (C) 2014, New Zealand Government,
2
+ # and is licensed under the GNU General Public License, version 3.
3
+ # See https://github.com/DigitalNZ/supplejack_client for details.
4
+ #
5
+ # Supplejack was created by DigitalNZ at the National Library of NZ
6
+ # and the Department of Internal Affairs. http://digitalnz.org/supplejack
7
+
8
+ module Supplejack
9
+
10
+ # The +UserSetRelation+ class provides ActiveRecord like functionality to the
11
+ # relationship between a User object and it's UserSet objects.
12
+ #
13
+ # @exmaple
14
+ # user = Supplejack::User.find(1)
15
+ #
16
+ # user.sets.build({name: "Dogs and cats"}) => Returns a new UserSet object linked to the User
17
+ # user.sets.find(123) => Return a UserSet object which belongs to the User
18
+ # user.sets.order(:name) => Return a array of UserSet objects ordered by name
19
+ #
20
+ class UserSetRelation
21
+ include Supplejack::Request
22
+
23
+ attr_reader :user
24
+
25
+ def initialize(user)
26
+ @user = user
27
+ end
28
+
29
+ # Returns an array of UserSet objects and memoizes the array
30
+ #
31
+ def sets
32
+ @sets ||= self.fetch_sets
33
+ end
34
+
35
+ # Initialize an array of UserSet objects and orders them by priority.
36
+ #
37
+ # @return [ Array ] A Array of +Supplejack::UserSet+ objects
38
+ #
39
+ def fetch_sets
40
+ response = sets_response
41
+ sets_array = response["sets"] || []
42
+ @sets = sets_array.map {|attributes| Supplejack::UserSet.new(attributes) }.sort_by { |set| set.priority }
43
+ end
44
+
45
+ # Execute a GET request to the API to retrieve the user_sets from a User.
46
+ # It caches the response from the API for a day. The cache is invalidated
47
+ # every time any set for the user changes.
48
+ #
49
+ # @return [ Hash ] A hash parsed from a JSON string. See the API Documentation for more details.
50
+ #
51
+ def sets_response
52
+ params = {}
53
+
54
+ if user.use_own_api_key?
55
+ path = "/sets"
56
+ params[:api_key] = user.api_key
57
+ else
58
+ path = "/users/#{user.api_key}/sets"
59
+ end
60
+
61
+ if Supplejack.enable_caching
62
+ Rails.cache.fetch(path, expires_in: 1.day) do
63
+ get(path, params)
64
+ end
65
+ else
66
+ get(path, params)
67
+ end
68
+ end
69
+
70
+ # Finds a UserSet object with the provided ID that belongs to the current
71
+ # User
72
+ #
73
+ # @param [ String ] A 24 character string representing the UserSet ID
74
+ #
75
+ # @return [ Supplejack::UserSet ] A UserSet object
76
+ #
77
+ def find(user_set_id)
78
+ Supplejack::UserSet.find(user_set_id, self.user.api_key)
79
+ end
80
+
81
+ # Initializes a new UserSet object and links it to the current User
82
+ #
83
+ # @param [ Hash ] A hash with the UserSet field names and values
84
+ #
85
+ # @return [ Supplejack::UserSet] A new UserSet object
86
+ #
87
+ def build(attributes={})
88
+ user_set = Supplejack::UserSet.new(attributes)
89
+ user_set.api_key = user.api_key
90
+ user_set
91
+ end
92
+
93
+ # Build and persist a UserSet object with the provided attributes
94
+ #
95
+ # @param [ Hash ] A hash with the UserSet field names and values
96
+ #
97
+ # @return [ Supplejack::UserSet ] A persisted UserSet object
98
+ #
99
+ def create(attributes={})
100
+ user_set = self.build(attributes)
101
+ user_set.save
102
+ user_set
103
+ end
104
+
105
+ # Return a array of UserSet objects ordered by the priority first and then
106
+ # in ascending order by the specified attribute.
107
+ #
108
+ # The only exception is for the "updated_at" attribute, for which ignores
109
+ # the priority and orders on descending order.
110
+ #
111
+ # @param [ Symbol ] A symbol with the attribute to order the UserSet objects on.
112
+ #
113
+ # @return [ Array ] A array of Supplejack::UserSet objects.
114
+ #
115
+ def order(attribute)
116
+ @sets = sets.sort_by do |set|
117
+ value = set.send(attribute)
118
+ value = value.downcase if value.is_a?(String)
119
+ attribute == :updated_at ? value : [set.priority, value]
120
+ end
121
+ @sets = @sets.reverse if attribute == :updated_at
122
+ @sets
123
+ end
124
+
125
+ # Returns an array of all UserSet objects for the current User
126
+ #
127
+ def all
128
+ self.sets
129
+ end
130
+
131
+ # Any method missing on this class is delegated to the UserSet objects array
132
+ # so that the developer can easily execute any Array method on the UserSetRelation
133
+ #
134
+ # @example
135
+ # user.sets.each .... => Iterate through the UserSet objects array
136
+ # user.sets.size => Get the size of the UserSet objects array
137
+ #
138
+ def method_missing(method, *args, &block)
139
+ sets.send(method, *args, &block)
140
+ end
141
+
142
+ end
143
+ end
@@ -0,0 +1,120 @@
1
+ # The Supplejack Client code is Crown copyright (C) 2014, New Zealand Government,
2
+ # and is licensed under the GNU General Public License, version 3.
3
+ # See https://github.com/DigitalNZ/supplejack_client for details.
4
+ #
5
+ # Supplejack was created by DigitalNZ at the National Library of NZ
6
+ # and the Department of Internal Affairs. http://digitalnz.org/supplejack
7
+
8
+ module Supplejack
9
+ module Util
10
+
11
+ class << self
12
+
13
+ #
14
+ # Return a array no matter what.
15
+ #
16
+ def array(object)
17
+ case object
18
+ when Array
19
+ object
20
+ when NilClass
21
+ []
22
+ else
23
+ [object]
24
+ end
25
+ end
26
+
27
+ #
28
+ # Try to parse any string into a Time object
29
+ #
30
+ def time(time)
31
+ begin
32
+ if time.is_a?(String)
33
+ time = Time.parse(time)
34
+ elsif time.is_a?(Time) || time.is_a?(DateTime)
35
+ time = time
36
+ end
37
+ rescue
38
+ time = nil
39
+ end
40
+
41
+ time
42
+ end
43
+ #
44
+ # Perform a deep merge of hashes, returning the result as a new hash.
45
+ # See #deep_merge_into for rules used to merge the hashes
46
+ #
47
+ # ==== Parameters
48
+ #
49
+ # left<Hash>:: Hash to merge
50
+ # right<Hash>:: The other hash to merge
51
+ #
52
+ # ==== Returns
53
+ #
54
+ # Hash:: New hash containing the given hashes deep-merged.
55
+ #
56
+ def deep_merge(left, right)
57
+ deep_merge_into({}, left, right)
58
+ end
59
+
60
+ #
61
+ # Perform a deep merge of the right hash into the left hash
62
+ #
63
+ # ==== Parameters
64
+ #
65
+ # left:: Hash to receive merge
66
+ # right:: Hash to merge into left
67
+ #
68
+ # ==== Returns
69
+ #
70
+ # Hash:: left
71
+ #
72
+ def deep_merge!(left, right)
73
+ deep_merge_into(left, left, right)
74
+ end
75
+
76
+ private
77
+
78
+ #
79
+ # Deep merge two hashes into a third hash, using rules that produce nice
80
+ # merged parameter hashes. The rules are as follows, for a given key:
81
+ #
82
+ # * If only one hash has a value, or if both hashes have the same value,
83
+ # just use the value.
84
+ # * If either of the values is not a hash, create arrays out of both
85
+ # values and concatenate them.
86
+ # * Otherwise, deep merge the two values (which are both hashes)
87
+ #
88
+ # ==== Parameters
89
+ #
90
+ # destination<Hash>:: Hash into which to perform the merge
91
+ # left<Hash>:: One hash to merge
92
+ # right<Hash>:: The other hash to merge
93
+ #
94
+ # ==== Returns
95
+ #
96
+ # Hash:: destination
97
+ #
98
+ def deep_merge_into(destination, left, right)
99
+ left.to_hash.symbolize_keys!
100
+ right.to_hash.symbolize_keys!
101
+ left.each_pair do |name, left_value|
102
+ right_value = right[name] if right
103
+ destination[name] =
104
+ if right_value.nil? || left_value == right_value
105
+ left_value
106
+ elsif !left_value.respond_to?(:each_pair) || !right_value.respond_to?(:each_pair)
107
+ Array(left_value) + Array(right_value)
108
+ else
109
+ merged_value = {}
110
+ deep_merge_into(merged_value, left_value, right_value)
111
+ end
112
+ end
113
+ left_keys = Set.new(left.keys)
114
+ destination.merge!(right.reject { |k, v| left_keys.include?(k) })
115
+ destination
116
+ end
117
+ end
118
+
119
+ end
120
+ end
@@ -0,0 +1,10 @@
1
+ # The Supplejack Client code is Crown copyright (C) 2014, New Zealand Government,
2
+ # and is licensed under the GNU General Public License, version 3.
3
+ # See https://github.com/DigitalNZ/supplejack_client for details.
4
+ #
5
+ # Supplejack was created by DigitalNZ at the National Library of NZ
6
+ # and the Department of Internal Affairs. http://digitalnz.org/supplejack
7
+
8
+ module Supplejack
9
+ VERSION = '1.0.1'
10
+ end
@@ -0,0 +1,29 @@
1
+ # The Supplejack Client code is Crown copyright (C) 2014, New Zealand Government,
2
+ # and is licensed under the GNU General Public License, version 3.
3
+ # See https://github.com/DigitalNZ/supplejack_client for details.
4
+ #
5
+ # Supplejack was created by DigitalNZ at the National Library of NZ
6
+ # and the Department of Internal Affairs. http://digitalnz.org/supplejack
7
+
8
+ require 'supplejack/config'
9
+ require 'supplejack/version'
10
+
11
+ module Supplejack
12
+ extend Config
13
+
14
+ require 'supplejack/engine'
15
+ require 'supplejack/exceptions'
16
+ require 'supplejack/log_subscriber'
17
+ require 'supplejack/record'
18
+ require "supplejack/request"
19
+ require 'supplejack/paginated_collection'
20
+ require 'supplejack/controllers/helpers'
21
+ require 'supplejack/url_formats/item_hash'
22
+ require 'supplejack/util'
23
+ require 'supplejack/facet'
24
+ require 'supplejack/user_set'
25
+ require 'supplejack/item_relation'
26
+ require 'supplejack/item'
27
+ require 'supplejack/user'
28
+ require 'supplejack/user_set_relation'
29
+ end
@@ -0,0 +1,23 @@
1
+ # The Supplejack Client code is Crown copyright (C) 2014, New Zealand Government,
2
+ # and is licensed under the GNU General Public License, version 3.
3
+ # See https://github.com/DigitalNZ/supplejack_client for details.
4
+ #
5
+ # Supplejack was created by DigitalNZ at the National Library of NZ
6
+ # and the Department of Internal Affairs. http://digitalnz.org/supplejack
7
+
8
+ require 'rubygems'
9
+ require 'bundler/setup'
10
+
11
+ Bundler.require(:default)
12
+
13
+ require 'supplejack_client'
14
+ require 'active_support/all'
15
+
16
+ RSpec.configure do |config|
17
+ # some (optional) config here
18
+ config.mock_with :rspec
19
+
20
+ config.treat_symbols_as_metadata_keys_with_true_values = true
21
+ config.filter_run :focus => true
22
+ config.run_all_when_everything_filtered = true
23
+ end
@@ -0,0 +1,277 @@
1
+ # The Supplejack Client code is Crown copyright (C) 2014, New Zealand Government,
2
+ # and is licensed under the GNU General Public License, version 3.
3
+ # See https://github.com/DigitalNZ/supplejack_client for details.
4
+ #
5
+ # Supplejack was created by DigitalNZ at the National Library of NZ
6
+ # and the Department of Internal Affairs. http://digitalnz.org/supplejack
7
+
8
+ require 'spec_helper'
9
+ require 'action_view'
10
+ require 'action_controller'
11
+ require 'rails_autolink/helpers'
12
+
13
+ include ActionView::Context
14
+
15
+ module FakeRoutes
16
+ def records_path(options={})
17
+ path = '/records'
18
+ path += "?#{options.to_query}" if options.any?
19
+ path
20
+ end
21
+
22
+ def record_path(id, options={})
23
+ path = "/records/#{id}"
24
+ path += "?#{options.to_query}" if options.any?
25
+ path
26
+ end
27
+
28
+ def url_for(options={})
29
+ options
30
+ end
31
+ end
32
+
33
+ def mock_record(stubs={})
34
+ (@mock_record ||= double(:record).as_null_object).tap do |record|
35
+ record.stub(stubs) unless stubs.empty?
36
+ end
37
+ end
38
+
39
+ class AdvancedSearch < Supplejack::Search
40
+ end
41
+
42
+ module Supplejack
43
+ module Controllers
44
+ describe Helpers do
45
+
46
+ before(:each) do
47
+ @c = ActionController::Base.new
48
+ @c.class.send(:include, FakeRoutes)
49
+ @c.class.send(:include, Supplejack::Controllers::Helpers)
50
+ @c.class.send(:include, ActionView::Helpers)
51
+ end
52
+
53
+ describe '#search' do
54
+ before(:each) do
55
+ @c.stub(:params) {{:text => 'dog'}}
56
+ end
57
+
58
+ it 'initializes a search object with the params' do
59
+ Supplejack::Search.should_receive(:new).with({:text => 'dog'})
60
+ @c.search
61
+ end
62
+
63
+ it 'tries to initialize with params[:search] ' do
64
+ @c.stub(:params) {{:search => {:text => 'cat'}}}
65
+ Supplejack::Search.should_receive(:new).with({:text => 'cat'})
66
+ @c.search
67
+ end
68
+
69
+ it 'initializes the search with the passed params' do
70
+ Supplejack::Search.should_receive(:new).with({:text => 'elephant'})
71
+ @c.search({:text => 'elephant'})
72
+ end
73
+
74
+ it 'uses the special Search class' do
75
+ Supplejack.stub(:search_klass) { 'AdvancedSearch' }
76
+ AdvancedSearch.should_receive(:new).with({:text => 'dog'})
77
+ @c.search
78
+ end
79
+
80
+ it 'memoizes the search object' do
81
+ @search = Supplejack::Search.new
82
+ Supplejack::Search.should_receive(:new).once.and_return(@search)
83
+ @c.search
84
+ @c.search
85
+ end
86
+ end
87
+
88
+ describe 'attribute' do
89
+ context 'nested attributes' do
90
+ before(:each) do
91
+ @user_set = Supplejack::UserSet.new(user: {name: 'Juanito'})
92
+ end
93
+
94
+ it 'supports nested attributes' do
95
+ @c.attribute(@user_set, 'user.name').should eq %{<p><strong>User.name: </strong>Juanito</p>}
96
+ end
97
+
98
+ it 'correctly uses the translation for the label' do
99
+ I18n.should_receive(:t).with('supplejack_user_sets.user.name', default: 'User.name') { 'By' }
100
+ @c.attribute(@user_set, 'user.name')
101
+ end
102
+ end
103
+
104
+ context 'single value' do
105
+ before(:each) do
106
+ @record = mock_record({:title => 'Wellington', :content_partner => '', :description => nil})
107
+ end
108
+
109
+ it 'returns the attribute name and its value' do
110
+ @c.attribute(@record, :title).should eq %{<p><strong>Title: </strong>Wellington</p>}
111
+ end
112
+
113
+ it 'uses a div instead of a p' do
114
+ @c.attribute(@record, :title, {:tag => :div}).should eq %{<div><strong>Title: </strong>Wellington</div>}
115
+ end
116
+
117
+ it 'does not use a tag if tag option is nil' do
118
+ @c.attribute(@record, :title, {:tag => nil}).should eq %{<strong>Title: </strong>Wellington}
119
+ end
120
+
121
+ it 'truncates the content to 5 characters' do
122
+ @c.attribute(@record, :title, {:limit => 8}).should eq %{<p><strong>Title: </strong>Welli...</p>}
123
+ end
124
+
125
+ it 'puts the label and the field value on seperate lines if label_inle is false' do
126
+ @c.attribute(@record, :title, {:label_inline => false}).should eq %{<p><strong>Title: </strong><br/>Wellington</p>}
127
+ end
128
+
129
+ it 'removes the label' do
130
+ @c.attribute(@record, :title, {:label => false}).should eq %{<p>Wellington</p>}
131
+ end
132
+
133
+ it 'doesn\'t display anything when the value is nil' do
134
+ @c.attribute(@record, :content_partner).should be_nil
135
+ @c.attribute(@record, :description).should be_nil
136
+ end
137
+
138
+ it 'displays span label tag' do
139
+ @c.attribute(@record, :title, {:label_tag => :span}).should eq %{<p><span>Title: </span>Wellington</p>}
140
+ end
141
+
142
+ it 'displays label tag with a class' do
143
+ @c.attribute(@record, :title, {:label_class => 'label'}).should eq %{<p><strong class="label">Title: </strong>Wellington</p>}
144
+ end
145
+
146
+ it 'uses the translation key' do
147
+ I18n.should_receive(:t).with('item.key', :default => 'Title').and_return('Title')
148
+ @c.attribute(@record, :title, {:trans_key => 'item.key'})
149
+ end
150
+
151
+ context ':link => true' do
152
+ it 'converts it to a URL when value is a url' do
153
+ url = "http://google.com/images"
154
+ @record = mock_record({:landing_url => url})
155
+ @c.attribute(@record, :landing_url, {:link => true}).should eq %{<p><strong>Landing_url: </strong>#{@c.link_to url, url}</p>}
156
+ end
157
+
158
+ it 'links to the URL when the value contains both a URL and text' do
159
+ url = 'http://google.com/images'
160
+ @record = mock_record({:source => "Image location #{url}"})
161
+ @c.attribute(@record, :source, {:link => true}).should eq %{<p><strong>Source: </strong>Image location #{@c.link_to url, url}</p>}
162
+ end
163
+
164
+ it 'converts it to a URL with the url pattern in :link and replaces the value' do
165
+ @record = mock_record({:subject => ['New Zealand']})
166
+ @c.attribute(@record, :subject, :link => '/records?i[subject_text]={{value}}').should eq %{<p><strong>Subject: </strong>#{@c.link_to "New Zealand", "/records?i[subject_text]=New Zealand"}</p>}
167
+ end
168
+
169
+ it 'returns nothing when value is nil' do
170
+ @c.attribute(@record, :description, {:link => true}).should be_nil
171
+ end
172
+ end
173
+
174
+ it 'returns nothing when value is "Not specified"' do
175
+ record = mock_record({:description => 'Not specified'})
176
+ @c.attribute(record, :description).should be_nil
177
+ end
178
+
179
+ it 'adds extra_html inside of the <p>' do
180
+ @c.attribute(@record, :title, {:extra_html => @c.content_tag(:span, 'Hi!')}).should eq %{<p><strong>Title: </strong>Wellington<span>Hi!</span></p>}
181
+ end
182
+
183
+ context 'default HTML values' do
184
+ it 'uses the tag defined in the config' do
185
+ Supplejack.stub(:attribute_tag) { :span }
186
+ @c.attribute(@record, :title).should eq %{<span><strong>Title: </strong>Wellington</span>}
187
+ end
188
+
189
+ it 'uses the label tag defined in the config' do
190
+ Supplejack.stub(:label_tag) { :b }
191
+ @c.attribute(@record, :title).should eq %{<p><b>Title: </b>Wellington</p>}
192
+ end
193
+
194
+ it 'uses the label class defined in the config' do
195
+ Supplejack.stub(:label_class) { 'label' }
196
+ @c.attribute(@record, :title).should eq %{<p><strong class="label">Title: </strong>Wellington</p>}
197
+ end
198
+ end
199
+ end
200
+
201
+ context 'multiple values' do
202
+ before(:each) do
203
+ @record = mock_record({:category => ['Images', 'Videos']})
204
+ end
205
+
206
+ it 'displays the values separated by commas' do
207
+ @c.attribute(@record, :category).should eq %{<p><strong>Category: </strong>Images, Videos</p>}
208
+ end
209
+
210
+ it 'displays the values separated by another delimiter' do
211
+ @c.attribute(@record, :category, {:delimiter => ':'}).should eq %{<p><strong>Category: </strong>Images:Videos</p>}
212
+ end
213
+
214
+ it 'limits the amount of values returned' do
215
+ @c.attribute(@record, :category, {:limit => 1}).should eq %{<p><strong>Category: </strong>Images</p>}
216
+ end
217
+
218
+ it 'limits the amount of values returned when less than 20' do
219
+ @record.stub(:category) { (1..30).to_a.map(&:to_s) }
220
+ @c.attribute(@record, :category, {:limit => 10}).should eq %{<p><strong>Category: </strong>1, 2, 3, 4, 5, 6, 7, 8, 9, 10</p>}
221
+ end
222
+
223
+ it 'generates links for every value' do
224
+ @link1 = @c.link_to('Images', "/records?#{{:i => {:category => 'Images'}}.to_query}")
225
+ @link2 = @c.link_to('Videos', "/records?#{{:i => {:category => 'Videos'}}.to_query}")
226
+ @c.attribute(@record, :category, {:link_path => "records_path"}).should eq %{<p><strong>Category: </strong>#{@link1}, #{@link2}</p>}
227
+ end
228
+
229
+ it 'converts every value to a URL when :link => true and value is a url' do
230
+ url1 = 'http://google.com/images'
231
+ url2 = 'http://yahoo.com/photos'
232
+ @record = mock_record({:landing_url => [url1, url2]})
233
+ @c.attribute(@record, :landing_url, {:link => true}).should eq %{<p><strong>Landing_url: </strong>#{@c.link_to url1, url1}, #{@c.link_to url2, url2}</p>}
234
+ end
235
+
236
+ it 'truncates the sum of all elements in the array' do
237
+ @record = mock_record({:description => ['This is a lengthy description', 'Some other stuff']})
238
+ @c.attribute(@record, :description, :limit => 40, :label => false).should eq "<p>This is a lengthy description, Some o...</p>"
239
+ end
240
+
241
+ it 'converts it to a URL with the url pattern in :link and replaces the value for each value' do
242
+ @c.attribute(@record, :category, :link => '/records?i[category]={{value}}').should eq %{<p><strong>Category: </strong>#{@c.link_to "Images", "/records?i[category]=Images"}, #{@c.link_to "Videos", "/records?i[category]=Videos"}</p>}
243
+ end
244
+ end
245
+
246
+ context 'multiple attributes' do
247
+ before(:each) do
248
+ @record = mock_record({:category => ['Images', 'Videos'], :creator => 'Federico', :object_url => nil, :source => nil})
249
+ end
250
+
251
+ it 'fetches values from multiple attributes' do
252
+ @c.attribute(@record, [:category, :creator]).should eq %{<p><strong>Category: </strong>Images, Videos, Federico</p>}
253
+ end
254
+
255
+ it 'returns nothing when both values are nil' do
256
+ @c.attribute(@record, [:object_url, :source], {:link => true}).should be_nil
257
+ end
258
+ end
259
+ end
260
+
261
+ describe '#attribute_link_replacement' do
262
+ it 'generates a link and replaces the value' do
263
+ @c.attribute_link_replacement('Images', '/records?i[category]={{value}}').should eq(@c.link_to('Images', '/records?i[category]=Images'))
264
+ end
265
+
266
+ it 'generates a link with the value as text and url' do
267
+ @c.attribute_link_replacement('http://google.comm/images', true).should eq(@c.link_to('http://google.comm/images', 'http://google.comm/images'))
268
+ end
269
+
270
+ it 'decodes the link_pattern' do
271
+ @c.attribute_link_replacement('Images', '/records?i[category]=%7B%7Bvalue%7D%7D').should eq(@c.link_to('Images', '/records?i[category]=Images'))
272
+ end
273
+ end
274
+
275
+ end
276
+ end
277
+ end