hubspot-ruby 0.1.7 → 0.1.8

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/hubspot-ruby.gemspec +42 -5
  3. data/lib/hubspot-ruby.rb +3 -0
  4. data/lib/hubspot/blog.rb +14 -48
  5. data/lib/hubspot/connection.rb +95 -0
  6. data/lib/hubspot/contact.rb +74 -91
  7. data/lib/hubspot/contact_list.rb +127 -0
  8. data/lib/hubspot/contact_properties.rb +12 -0
  9. data/lib/hubspot/deal.rb +29 -25
  10. data/lib/hubspot/exceptions.rb +2 -0
  11. data/lib/hubspot/form.rb +88 -4
  12. data/lib/hubspot/topic.rb +8 -24
  13. data/lib/hubspot/utils.rb +0 -51
  14. data/lib/hubspot/version.rb +1 -1
  15. data/spec/fixtures/vcr_cassettes/add_contacts_to_lists.yml +281 -0
  16. data/spec/fixtures/vcr_cassettes/contact_create.yml +34 -2
  17. data/spec/fixtures/vcr_cassettes/contact_create_existing_email.yml +34 -2
  18. data/spec/fixtures/vcr_cassettes/contact_create_invalid_email.yml +35 -3
  19. data/spec/fixtures/vcr_cassettes/contact_create_with_params.yml +34 -2
  20. data/spec/fixtures/vcr_cassettes/contact_destroy.yml +36 -4
  21. data/spec/fixtures/vcr_cassettes/contact_find_by_email_batch_mode.yml +509 -0
  22. data/spec/fixtures/vcr_cassettes/contact_find_by_id_batch_mode.yml +33 -0
  23. data/spec/fixtures/vcr_cassettes/contact_find_by_utk_batch_mode.yml +33 -0
  24. data/spec/fixtures/vcr_cassettes/contact_list_batch_find.yml +65 -0
  25. data/spec/fixtures/vcr_cassettes/contact_list_destroy.yml +63 -0
  26. data/spec/fixtures/vcr_cassettes/contact_list_example.yml +33 -0
  27. data/spec/fixtures/vcr_cassettes/contact_list_find.yml +96 -0
  28. data/spec/fixtures/vcr_cassettes/contact_list_refresh.yml +33 -0
  29. data/spec/fixtures/vcr_cassettes/contact_list_update.yml +36 -0
  30. data/spec/fixtures/vcr_cassettes/contacts_among_list.yml +189 -0
  31. data/spec/fixtures/vcr_cassettes/create_form.yml +39 -0
  32. data/spec/fixtures/vcr_cassettes/create_list.yml +36 -0
  33. data/spec/fixtures/vcr_cassettes/create_list_with_filters.yml +36 -0
  34. data/spec/fixtures/vcr_cassettes/deal_create.yml +29 -0
  35. data/spec/fixtures/vcr_cassettes/deal_find.yml +56 -0
  36. data/spec/fixtures/vcr_cassettes/destroy_deal.yml +110 -0
  37. data/spec/fixtures/vcr_cassettes/fail_to_create_form.yml +35 -0
  38. data/spec/fixtures/vcr_cassettes/fail_to_create_list.yml +35 -0
  39. data/spec/fixtures/vcr_cassettes/field_among_form.yml +34 -0
  40. data/spec/fixtures/vcr_cassettes/fields_among_form.yml +35 -0
  41. data/spec/fixtures/vcr_cassettes/find_all_contacts.yml +39 -0
  42. data/spec/fixtures/vcr_cassettes/find_all_dynamic_lists.yml +104 -0
  43. data/spec/fixtures/vcr_cassettes/find_all_forms.yml +15378 -0
  44. data/spec/fixtures/vcr_cassettes/find_all_lists.yml +138 -0
  45. data/spec/fixtures/vcr_cassettes/find_all_recent_contacts.yml +33 -0
  46. data/spec/fixtures/vcr_cassettes/find_all_stastic_lists.yml +21876 -0
  47. data/spec/fixtures/vcr_cassettes/form_destroy.yml +64 -0
  48. data/spec/fixtures/vcr_cassettes/form_example.yml +39 -0
  49. data/spec/fixtures/vcr_cassettes/form_find.yml +69 -0
  50. data/spec/fixtures/vcr_cassettes/form_submit_data.yml +130 -0
  51. data/spec/fixtures/vcr_cassettes/form_update.yml +77 -0
  52. data/spec/fixtures/vcr_cassettes/one_month_blog_posts_filter_state.yml +5168 -0
  53. data/spec/fixtures/vcr_cassettes/remove_contacts_from_lists.yml +315 -0
  54. data/spec/lib/hubspot/blog_spec.rb +4 -3
  55. data/spec/lib/hubspot/connection_spec.rb +112 -0
  56. data/spec/lib/hubspot/contact_list_spec.rb +249 -0
  57. data/spec/lib/hubspot/contact_properties_spec.rb +8 -0
  58. data/spec/lib/hubspot/contact_spec.rb +110 -54
  59. data/spec/lib/hubspot/deal_spec.rb +11 -0
  60. data/spec/lib/hubspot/form_spec.rb +157 -10
  61. data/spec/lib/hubspot/utils_spec.rb +0 -67
  62. data/spec/live/deals_integration_spec.rb +35 -0
  63. data/spec/spec_helper.rb +2 -0
  64. data/spec/support/tests_helper.rb +17 -0
  65. metadata +70 -33
@@ -0,0 +1,127 @@
1
+ module Hubspot
2
+ #
3
+ # HubSpot Contact lists API
4
+ #
5
+ class ContactList
6
+ LISTS_PATH = '/contacts/v1/lists'
7
+ LIST_PATH = '/contacts/v1/lists/:list_id'
8
+ LIST_BATCH_PATH = LISTS_PATH + '/batch'
9
+ CONTACTS_PATH = LIST_PATH + '/contacts/all'
10
+ RECENT_CONTACTS_PATH = LIST_PATH + '/contacts/recent'
11
+ ADD_CONTACT_PATH = LIST_PATH + '/add'
12
+ REMOVE_CONTACT_PATH = LIST_PATH + '/remove'
13
+ REFRESH_PATH = LIST_PATH + '/refresh'
14
+
15
+ class << self
16
+ # {http://developers.hubspot.com/docs/methods/lists/create_list}
17
+ def create!(opts={})
18
+ dynamic = opts.delete(:dynamic) { false }
19
+ portal_id = opts.delete(:portal_id) { Hubspot::Config.portal_id }
20
+
21
+ response = Hubspot::Connection.post_json(LISTS_PATH, params: {}, body: opts.merge({ dynamic: dynamic, portal_id: portal_id}) )
22
+ new(response)
23
+ end
24
+
25
+ # {http://developers.hubspot.com/docs/methods/lists/get_lists}
26
+ # {http://developers.hubspot.com/docs/methods/lists/get_static_lists}
27
+ # {http://developers.hubspot.com/docs/methods/lists/get_dynamic_lists}
28
+ def all(opts={})
29
+ static = opts.delete(:static) { false }
30
+ dynamic = opts.delete(:dynamic) { false }
31
+
32
+ # NOTE: As opposed of what the documentation says, getting the static or dynamic lists returns all the lists, not only 20 lists
33
+ path = LISTS_PATH + (static ? '/static' : dynamic ? '/dynamic' : '')
34
+ response = Hubspot::Connection.get_json(path, opts)
35
+ response['lists'].map { |l| new(l) }
36
+ end
37
+
38
+ # {http://developers.hubspot.com/docs/methods/lists/get_list}
39
+ # {http://developers.hubspot.com/docs/methods/lists/get_batch_lists}
40
+ def find(ids)
41
+ batch_mode, path, params = case ids
42
+ when Integer then [false, LIST_PATH, { list_id: ids }]
43
+ when String then [false, LIST_PATH, { list_id: ids.to_i }]
44
+ when Array then [true, LIST_BATCH_PATH, { batch_list_id: ids.map(&:to_i) }]
45
+ else raise Hubspot::InvalidParams, 'expecting Integer or Array of Integers parameter'
46
+ end
47
+
48
+ response = Hubspot::Connection.get_json(path, params)
49
+ batch_mode ? response['lists'].map { |l| new(l) } : new(response)
50
+ end
51
+ end
52
+
53
+ attr_reader :id
54
+ attr_reader :portal_id
55
+ attr_reader :name
56
+ attr_reader :dynamic
57
+ attr_reader :properties
58
+
59
+ def initialize(hash)
60
+ self.send(:assign_properties, hash)
61
+ end
62
+
63
+ # {http://developers.hubspot.com/docs/methods/lists/update_list}
64
+ def update!(opts={})
65
+ response = Hubspot::Connection.post_json(LIST_PATH, params: { list_id: @id }, body: opts)
66
+ self.send(:assign_properties, response)
67
+ self
68
+ end
69
+
70
+ # {http://developers.hubspot.com/docs/methods/lists/delete_list}
71
+ def destroy!
72
+ response = Hubspot::Connection.delete_json(LIST_PATH, { list_id: @id })
73
+ @destroyed = (response.code == 204)
74
+ end
75
+
76
+ # {http://developers.hubspot.com/docs/methods/lists/get_list_contacts}
77
+ def contacts(opts={})
78
+ # NOTE: caching functionality can be dependant of the nature of the list, if dynamic or not ...
79
+ bypass_cache = opts.delete(:bypass_cache) { false }
80
+ recent = opts.delete(:recent) { false }
81
+
82
+ if bypass_cache || @contacts.nil?
83
+ path = recent ? RECENT_CONTACTS_PATH : CONTACTS_PATH
84
+ opts[:list_id] = @id
85
+
86
+ response = Hubspot::Connection.get_json(path, Hubspot::ContactProperties.add_default_parameters(opts))
87
+ @contacts = response['contacts'].map { |c| Hubspot::Contact.new(c) }
88
+ else
89
+ @contacts
90
+ end
91
+ end
92
+
93
+ # {http://developers.hubspot.com/docs/methods/lists/refresh_list}
94
+ def refresh
95
+ response = Hubspot::Connection.post_json(REFRESH_PATH, params: { list_id: @id, no_parse: true }, body: {})
96
+ response.code == 204
97
+ end
98
+
99
+ # {http://developers.hubspot.com/docs/methods/lists/add_contact_to_list}
100
+ def add(contacts)
101
+ contact_ids = [contacts].flatten.uniq.compact.map(&:vid)
102
+ response = Hubspot::Connection.post_json(ADD_CONTACT_PATH, params: { list_id: @id }, body: { vids: contact_ids })
103
+ response['updated'].sort == contact_ids.sort
104
+ end
105
+
106
+ # {http://developers.hubspot.com/docs/methods/lists/remove_contact_from_list}
107
+ def remove(contacts)
108
+ contact_ids = [contacts].flatten.uniq.compact.map(&:vid)
109
+ response = Hubspot::Connection.post_json(REMOVE_CONTACT_PATH, params: { list_id: @id }, body: { vids: contact_ids })
110
+ response['updated'].sort == contact_ids.sort
111
+ end
112
+
113
+ def destroyed?
114
+ !!@destroyed
115
+ end
116
+
117
+ private
118
+
119
+ def assign_properties(hash)
120
+ @id = hash['listId']
121
+ @portal_id = hash['portalId']
122
+ @name = hash['name']
123
+ @dynamic = hash['dynamic']
124
+ @properties = hash
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,12 @@
1
+ module Hubspot
2
+ class ContactProperties
3
+ class << self
4
+ # TODO: properties can be set as configuration
5
+ # TODO: find the way how to set a list of Properties + merge same property key if present from opts
6
+ def add_default_parameters(opts={})
7
+ properties = 'email'
8
+ opts.merge(property: properties)
9
+ end
10
+ end
11
+ end
12
+ end
data/lib/hubspot/deal.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'hubspot/utils'
2
- require 'httparty'
3
2
 
4
3
  module Hubspot
5
4
  #
@@ -8,6 +7,10 @@ module Hubspot
8
7
  # {http://developers.hubspot.com/docs/methods/deals/deals_overview}
9
8
  #
10
9
  class Deal
10
+ CREATE_DEAL_PATH = "/deals/v1/deal"
11
+ DEAL_PATH = "/deals/v1/deal/:deal_id"
12
+ RECENT_UPDATED_PATH = "/deals/v1/deal/recent/modified"
13
+ UPDATE_DEAL_PATH = '/deals/v1/deal/:deal_id'
11
14
 
12
15
  attr_reader :properties
13
16
  attr_reader :portal_id
@@ -15,10 +18,6 @@ module Hubspot
15
18
  attr_reader :company_ids
16
19
  attr_reader :vids
17
20
 
18
- CREATE_DEAL_PATH = "/deals/v1/deal"
19
- DEAL_PATH = "/deals/v1/deal/:deal_id"
20
- RECENT_UPDATED_PATH = "/deals/v1/deal/recent/modified"
21
-
22
21
  def initialize(response_hash)
23
22
  @portal_id = response_hash["portalId"]
24
23
  @deal_id = response_hash["dealId"]
@@ -29,21 +28,17 @@ module Hubspot
29
28
 
30
29
  class << self
31
30
  def create!(portal_id, company_ids, vids, params={})
32
- url = Hubspot::Utils.generate_url(CREATE_DEAL_PATH).concat("&portalId=#{portal_id}")
31
+ #TODO: clean following hash, Hubspot::Utils should do the trick
33
32
  associations_hash = {"portalId" => portal_id, "associations" => { "associatedCompanyIds" => company_ids, "associatedVids" => vids}}
34
33
  post_data = associations_hash.merge({ properties: Hubspot::Utils.hash_to_properties(params, key_name: "name") })
35
- resp = HTTParty.post(url, body: post_data.to_json, headers: {"Content-Type" => "application/json"})
36
- Hubspot::Deal.new(resp.parsed_response)
34
+
35
+ response = Hubspot::Connection.post_json(CREATE_DEAL_PATH, params: {}, body: post_data )
36
+ new(response)
37
37
  end
38
38
 
39
39
  def find(deal_id)
40
- url = Hubspot::Utils.generate_url(DEAL_PATH, {deal_id: deal_id})
41
- resp = HTTParty.get(url, format: :json)
42
- if resp.success?
43
- Hubspot::Deal.new(resp.parsed_response)
44
- else
45
- nil
46
- end
40
+ response = Hubspot::Connection.get_json(DEAL_PATH, { deal_id: deal_id })
41
+ new(response)
47
42
  end
48
43
 
49
44
  # Find recent updated deals.
@@ -51,28 +46,37 @@ module Hubspot
51
46
  # @param count [Integer] the amount of deals to return.
52
47
  # @param offset [Integer] pages back through recent contacts.
53
48
  def recent(opts = {})
54
- url = Hubspot::Utils.generate_url(RECENT_UPDATED_PATH, opts)
55
- request = HTTParty.get(url, format: :json)
56
-
57
- raise(Hubspot::RequestError.new(request)) unless request.success?
58
-
59
- found = request.parsed_response['results']
60
- return found.map{|h| new(h) }
49
+ response = Hubspot::Connection.get_json(RECENT_UPDATED_PATH, opts)
50
+ response['results'].map { |d| new(d) }
61
51
  end
52
+
62
53
  end
63
54
 
64
55
  # Archives the contact in hubspot
65
56
  # {https://developers.hubspot.com/docs/methods/contacts/delete_contact}
66
57
  # @return [TrueClass] true
67
58
  def destroy!
68
- url = Hubspot::Utils.generate_url(DEAL_PATH, {deal_id: deal_id})
69
- request = HTTParty.delete(url, format: :json)
70
- raise(Hubspot::RequestError.new(request)) unless request.success?
59
+ response = Hubspot::Connection.delete_json(DEAL_PATH, {deal_id: deal_id})
71
60
  @destroyed = true
72
61
  end
73
62
 
74
63
  def destroyed?
75
64
  !!@destroyed
76
65
  end
66
+
67
+ def [](property)
68
+ @properties[property]
69
+ end
70
+
71
+ # Updates the properties of a deal
72
+ # {https://developers.hubspot.com/docs/methods/deals/update_deal}
73
+ # @param params [Hash] hash of properties to update
74
+ # @return [Hubspot::Deal] self
75
+ def update!(params)
76
+ query = {"properties" => Hubspot::Utils.hash_to_properties(params.stringify_keys!, key_name: 'name')}
77
+ response = Hubspot::Connection.put_json(UPDATE_DEAL_PATH, params: { deal_id: deal_id }, body: query)
78
+ @properties.merge!(params)
79
+ self
80
+ end
77
81
  end
78
82
  end
@@ -13,4 +13,6 @@ module Hubspot
13
13
  class ConfigurationError < StandardError; end
14
14
  class MissingInterpolation < StandardError; end
15
15
  class ContactExistsError < RequestError; end
16
+ class InvalidParams < StandardError; end
17
+ class ApiError < StandardError; end
16
18
  end
data/lib/hubspot/form.rb CHANGED
@@ -1,11 +1,95 @@
1
1
  module Hubspot
2
+ #
3
+ # HubSpot Form API
4
+ #
5
+ # {https://developers.hubspot.com/docs/methods/forms/forms_overview}
6
+ #
2
7
  class Form
3
- def initialize(form_guid)
4
- @form_guid = form_guid
8
+ FORMS_PATH = '/contacts/v1/forms'
9
+ FORM_PATH = '/contacts/v1/forms/:form_guid'
10
+ FIELDS_PATH = '/contacts/v1/fields/:form_guid'
11
+ FIELD_PATH = FIELDS_PATH + '/:field_name'
12
+ SUBMIT_DATA_PATH = '/uploads/form/v2/:portal_id/:form_guid'
13
+
14
+ class << self
15
+ # {https://developers.hubspot.com/docs/methods/forms/create_form}
16
+ def create!(opts={})
17
+ response = Hubspot::Connection.post_json(FORMS_PATH, params: {}, body: opts)
18
+ new(response)
19
+ end
20
+
21
+ def all
22
+ response = Hubspot::Connection.get_json(FORMS_PATH, {})
23
+ response.map { |f| new(f) }
24
+ end
25
+
26
+ # {https://developers.hubspot.com/docs/methods/forms/get_form}
27
+ def find(guid)
28
+ response = Hubspot::Connection.get_json(FORM_PATH, { form_guid: guid })
29
+ new(response)
30
+ end
31
+ end
32
+
33
+ attr_reader :guid
34
+ attr_reader :fields
35
+ attr_reader :properties
36
+
37
+ def initialize(hash)
38
+ self.send(:assign_properties, hash)
39
+ end
40
+
41
+ # {https://developers.hubspot.com/docs/methods/forms/get_fields}
42
+ # {https://developers.hubspot.com/docs/methods/forms/get_field}
43
+ def fields(opts={})
44
+ bypass_cache = opts.delete(:bypass_cache) { false }
45
+ field_name = opts.delete(:only) { nil }
46
+
47
+ if field_name
48
+ field_name = field_name.to_s
49
+ if bypass_cache || @fields.nil? || @fields.empty?
50
+ response = Hubspot::Connection.get_json(FIELD_PATH, { form_guid: @guid, field_name: field_name })
51
+ response
52
+ else
53
+ @fields.detect { |f| f['name'] == field_name }
54
+ end
55
+ else
56
+ if bypass_cache || @fields.nil? || @fields.empty?
57
+ response = Hubspot::Connection.get_json(FIELDS_PATH, { form_guid: @guid })
58
+ @fields = response
59
+ end
60
+ @fields
61
+ end
5
62
  end
63
+
64
+ # {https://developers.hubspot.com/docs/methods/forms/submit_form}
65
+ def submit(opts={})
66
+ response = Hubspot::FormsConnection.submit(SUBMIT_DATA_PATH, params: { form_guid: @guid }, body: opts)
67
+ [204, 302].include?(response.code)
68
+ end
69
+
70
+ # {https://developers.hubspot.com/docs/methods/forms/update_form}
71
+ def update!(opts={})
72
+ response = Hubspot::Connection.post_json(FORM_PATH, params: { form_guid: @guid }, body: opts)
73
+ self.send(:assign_properties, response)
74
+ self
75
+ end
76
+
77
+ # {https://developers.hubspot.com/docs/methods/forms/delete_form}
78
+ def destroy!
79
+ response = Hubspot::Connection.delete_json(FORM_PATH, { form_guid: @guid })
80
+ @destroyed = (response.code == 204)
81
+ end
82
+
83
+ def destroyed?
84
+ !!@destroyed
85
+ end
86
+
87
+ private
6
88
 
7
- def url
8
- Hubspot::Utils.generate_url("/uploads/form/v2/:portal_id/:form_guid", {form_guid: @form_guid}, {base_url: "https://forms.hubspot.com", hapikey: false})
89
+ def assign_properties(hash)
90
+ @guid = hash['guid']
91
+ @fields = hash['fields']
92
+ @properties = hash
9
93
  end
10
94
  end
11
95
  end
data/lib/hubspot/topic.rb CHANGED
@@ -1,42 +1,26 @@
1
- require 'hubspot/utils'
2
- require 'httparty'
3
-
4
1
  module Hubspot
5
2
  #
6
3
  # HubSpot Topics API
7
4
  #
8
5
  class Topic
9
- TOPIC_LIST_PATH = "/content/api/v2/topics"
10
- GET_TOPIC_BY_ID_PATH = "/content/api/v2/topics/:topic_id"
6
+ TOPICS_PATH = "/content/api/v2/topics"
7
+ TOPIC_PATH = "/content/api/v2/topics/:topic_id"
11
8
 
12
9
  class << self
13
10
  # Lists the topics
14
11
  # {https://developers.hubspot.com/docs/methods/blogv2/get_topics)
15
- # @return [Hubspot::Topic, []] array of topics or empty_array
12
+ # @return [Hubspot::Topic] array of topics
16
13
  def list
17
- url = Hubspot::Utils.generate_url(TOPIC_LIST_PATH)
18
- resp = HTTParty.get(url, format: :json)
19
- if resp.success?
20
- resp.parsed_response['objects'].map do |topic_hash|
21
- Topic.new(topic_hash)
22
- end
23
- else
24
- []
25
- end
14
+ response = Hubspot::Connection.get_json(TOPICS_PATH, {})
15
+ response['objects'].map { |t| new(t) }
26
16
  end
27
17
 
28
18
  # Finds the details for a specific topic_id
29
19
  # {https://developers.hubspot.com/docs/methods/blogv2/get_topics_topic_id }
30
- # @return Hubspot::Topic or nil
31
-
20
+ # @return Hubspot::Topic
32
21
  def find_by_topic_id(id)
33
- url = Hubspot::Utils.generate_url(GET_TOPIC_BY_ID_PATH, topic_id: id)
34
- resp = HTTParty.get(url, format: :json)
35
- if resp.success?
36
- Topic.new(resp.parsed_response)
37
- else
38
- nil
39
- end
22
+ response = Hubspot::Connection.get_json(TOPIC_PATH, { topic_id: id })
23
+ new(response)
40
24
  end
41
25
  end
42
26
 
data/lib/hubspot/utils.rb CHANGED
@@ -13,57 +13,6 @@ module Hubspot
13
13
  key_name = opts[:key_name] || "property"
14
14
  hash.map{ |k,v| { key_name => k.to_s, "value" => v}}
15
15
  end
16
-
17
- # Generate the API URL for the request
18
- #
19
- # @param path [String] The path of the request with leading "/". Parts starting with a ":" will be interpolated
20
- # @param params [Hash] params to be included in the query string or interpolated into the url.
21
- #
22
- # @return [String]
23
- #
24
- def generate_url(path, params={}, options={})
25
- Hubspot::Config.ensure! :hapikey
26
- path = path.clone
27
- params = params.clone
28
- base_url = options[:base_url] || Hubspot::Config.base_url
29
- params["hapikey"] = Hubspot::Config.hapikey unless options[:hapikey] == false
30
-
31
- if path =~ /:portal_id/
32
- Hubspot::Config.ensure! :portal_id
33
- params["portal_id"] = Hubspot::Config.portal_id if path =~ /:portal_id/
34
- end
35
-
36
- params.each do |k,v|
37
- if path.match(":#{k}")
38
- path.gsub!(":#{k}",v.to_s)
39
- params.delete(k)
40
- end
41
- end
42
- raise(Hubspot::MissingInterpolation.new("Interpolation not resolved")) if path =~ /:/
43
- query = params.map{ |k,v| param_string(k,v) }.join("&")
44
- path += "?" if query.present?
45
- base_url + path + query
46
- end
47
-
48
-
49
- private
50
-
51
- def converted_value(value)
52
- if (value.is_a?(Time))
53
- (value.to_i * 1000) # convert into milliseconds since epoch
54
- else
55
- value
56
- end
57
- end
58
-
59
- def param_string(key,value)
60
- if (key =~ /range/)
61
- raise "Value must be a range" unless value.is_a?(Range)
62
- "#{key}=#{converted_value(value.begin)}&#{key}=#{converted_value(value.end)}"
63
- else
64
- "#{key}=#{converted_value(value)}"
65
- end
66
- end
67
16
  end
68
17
  end
69
18
  end