helix 0.0.2.7.pre → 0.0.2.8.pre

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/README.md CHANGED
@@ -44,11 +44,10 @@ rake reinstall_helix_rvm
44
44
 
45
45
  Using gem in a Gemfile
46
46
  ```shell
47
- gem 'helix', :git => git@github.com:Twistage/helix.git
47
+ gem 'helix', :git => 'git@github.com:Twistage/helix.git'
48
48
  ```
49
49
 
50
50
 
51
-
52
51
  Supported Ruby versions
53
52
  -----------------------
54
53
 
@@ -57,88 +56,26 @@ Supported Ruby versions
57
56
 
58
57
  How To
59
58
  ------
60
- Warning: How To is not currently finished, it may be inaccurate.
61
59
  ###Setup YAML
62
60
  ```yaml
63
61
  site: 'http://service.twistage.com'
64
- user: 'my_account@twistage.com'
65
- password: 'password123'
66
62
  company: 'my_company'
67
- license_key: '141a86b5c4091
63
+ license_key: '141a86b5c4091'
64
+ library_id: 'development'
65
+ ```
66
+ Boot up IRB in your console
67
+ ```shell
68
+ irb
68
69
  ```
69
70
  Load the YAML file as your config.
70
71
  ```ruby
72
+ require 'helix'
71
73
  Helix::Config.load("path/to/yaml.yml")
74
+ videos = Helix::Video.find_all
72
75
  ```
73
- ####Current CRUD methods supported by all models
74
- .create
75
- .find
76
- \#update
77
- \#destroy
78
76
 
79
- ####Current models
80
- Videos, Images, Albums, Tracks, Playlists
77
+ If no file is passed in Helix with default to './helix.yml'
81
78
 
82
- ###Videos
83
- #####Required fields: title, description, library, company, and source.
84
- ```ruby
85
- video = Helix::Video.create!( title: 'New Video',
86
- description: 'A video of new things',
87
- source: 'http://somesource.com/source.mp4'
88
- company: 'some_company',
89
- library: 'some_library')
90
- video.update({title: "New Title"})
91
- another_video = Helix::Video.find(some_guid)
92
- another_video.destroy
93
- ```
94
- ###Albums
95
- #####Required fields: title, library, company.
96
- ```ruby
97
- album = Helix::Album.create!( title: 'New Album',
98
- description: 'A album of new things',
99
- source: 'http://somesource.com/source.mp4'
100
- company: 'some_company',
101
- library: 'some_library')
102
- #Update for album is not currently supported
103
- another_album = Helix::Album.find(some_guid)
104
- another_album.destroy
105
- ```
106
- ###Images
107
- #####Required fields: title, description, library, company, and source.
108
- ```ruby
109
- image = Helix::Image.create!( title: 'New Image',
110
- description: 'A image of new things',
111
- source: 'http://somesource.com/source.jpg'
112
- company: 'some_company',
113
- library: 'some_library')
114
- image.update({title: "New Title"})
115
- another_image = Helix::Image.find(some_guid)
116
- another_image.destroy
117
- ```
118
- ###Tracks
119
- #####Required fields: title, description, library, company, and source.
120
- ```ruby
121
- track = Helix::Track.create!( title: 'New Track',
122
- description: 'A track of new things',
123
- source: 'http://somesource.com/source.mp3'
124
- company: 'some_company',
125
- library: 'some_library')
126
- track.update({title: "New Title"})
127
- another_track = Helix::Track.find(some_guid)
128
- another_track.destroy
129
- ```
130
- ###Playlists
131
- #####Required fields: title, library, company.
132
- ```ruby
133
- playlist = Helix::Playlist.create!( title: 'New Playlist',
134
- description: 'A playlist of new things',
135
- source: 'http://somesource.com/source.mp4'
136
- company: 'some_company',
137
- library: 'some_library')
138
- playlist.update({title: "New Title"})
139
- another_playlist = Helix::Playlist.find(some_guid)
140
- another_playlist.destroy
141
- ```
142
79
 
143
80
  More Information
144
81
  ----------------
@@ -163,4 +100,4 @@ The names and logos for twistage are trademarks of Twistage, Inc.
163
100
  License
164
101
  -------
165
102
 
166
- Helix is Copyright © 2008-2012 Twistage, Inc.
103
+ Helix is Copyright © 2008-2012 Twistage, Inc.
@@ -1,3 +1,5 @@
1
+ require 'helix/restful'
2
+ require 'helix/uploadable'
1
3
  require 'helix/durationed_media'
2
4
  require 'helix/video'
3
5
  require 'helix/track'
@@ -24,7 +24,7 @@ module Helix
24
24
 
25
25
  def self.known_attributes
26
26
  [:title, :description]
27
- end
27
+ end
28
28
 
29
29
  end
30
30
 
@@ -3,6 +3,7 @@ require 'json'
3
3
  require 'yaml'
4
4
  require 'nori'
5
5
  require 'time'
6
+ require 'helix/exceptions'
6
7
 
7
8
  module Helix
8
9
  class Base
@@ -23,6 +24,7 @@ module Helix
23
24
  # @param [Hash] opts a hash of options for parameters passed into the HTTP GET
24
25
  # @return [Array] The array of instance objects for a class.
25
26
  def self.find_all(original_opts={})
27
+ raise Helix::NoConfigurationLoaded.new if config.nil?
26
28
  opts = original_opts.clone
27
29
  RestClient.log = 'helix.log' if opts.delete(:log)
28
30
  data_sets = get_data_sets(opts)
@@ -49,11 +51,11 @@ module Helix
49
51
  # @param [Hash] opts a hash of options for parameters passed into the HTTP GET
50
52
  # @return [Array] The array of attributes (for a model) in hash form.
51
53
  def self.get_data_sets(opts)
54
+ label = self.plural_resource_label
52
55
  url = config.build_url(content_type: opts[:content_type] || :xml,
53
- resource_label: self.plural_resource_label)
56
+ resource_label: label)
54
57
  # We allow opts[:sig_type] for internal negative testing only.
55
- raw_response = config.get_response(url, {sig_type: :view}.merge(opts))
56
- data_sets = raw_response[plural_resource_label]
58
+ data_sets = config.get_aggregated_data_sets(url, label, {sig_type: :view}.merge(opts))
57
59
  end
58
60
 
59
61
  # Creates a string that associates to the class id.
@@ -120,6 +122,14 @@ module Helix
120
122
  end
121
123
  alias_method :reload, :load
122
124
 
125
+ def to_json
126
+ {resource_label_sym => @attributes}.to_json
127
+ end
128
+
129
+ def to_xml
130
+ modified_attributes.to_xml({root: resource_label_sym})
131
+ end
132
+
123
133
  # Raises an error for missing method calls.
124
134
  #
125
135
  # @param [Symbol] method_sym The method attempting to be called.
@@ -171,6 +181,16 @@ module Helix
171
181
  attrs.merge({'custom_fields' => cfs})
172
182
  end
173
183
 
184
+ def modified_attributes
185
+ custom_fields = @attributes['custom_fields']
186
+ return @attributes if custom_fields.nil?
187
+ return @attributes if custom_fields.first['name'].nil?
188
+ new_cfs = custom_fields.inject({}) do |memo,cf|
189
+ memo.merge(cf['name'] => cf['value'])
190
+ end
191
+ @attributes.merge('custom_fields' => new_cfs)
192
+ end
193
+
174
194
  def self.resource_label_sym
175
195
  to_s.split('::').last.singularize.downcase.to_sym
176
196
  end
@@ -12,14 +12,16 @@ module Helix
12
12
 
13
13
  unless defined?(self::DEFAULT_FILENAME)
14
14
  DEFAULT_FILENAME = './helix.yml'
15
+ ITEMS_PER_PAGE = 100
15
16
  SCOPES = [:reseller, :company, :library]
16
17
  SIG_DURATION = 1200 # in minutes
18
+ STARTING_PAGE = 1
17
19
  TIME_OFFSET = 1000 * 60 # 1000 minutes, lower to give some margin of error
18
20
  VALID_SIG_TYPES = [ :ingest, :update, :view ]
19
21
  end
20
22
 
21
23
  attr_accessor :credentials
22
- attr_reader :signature_for, :signature_expiration_for
24
+ attr_reader :response, :signature_for, :signature_expiration_for
23
25
 
24
26
  # Creates a singleton of itself, setting the config
25
27
  # to a specified YAML file. If no file is specified the default
@@ -72,6 +74,25 @@ module Helix
72
74
  @signature_expiration_for = {}
73
75
  end
74
76
 
77
+ # Makes aggregated calls to get_response with pagination
78
+ # folding/injecting/accumulating the results into a single output set.
79
+ #
80
+ # @param [String] url the base part of the URL to be used
81
+ # @param [String] plural_resource_label: "videos", "tracks", etc.
82
+ # @param [Hash] original_opts a hash of options for building URL additions
83
+ # @return [Array] The accumulated attribute Hashes for ORM instances
84
+ def get_aggregated_data_sets(url, plural_resource_label, original_opts={})
85
+ data_sets, page, per_page = [], STARTING_PAGE
86
+ until last_page?
87
+ aggregation_opts = original_opts.merge(page: page, per_page: ITEMS_PER_PAGE)
88
+ raw_response = get_response(url, {sig_type: :view}.merge(aggregation_opts))
89
+ data_set = raw_response[plural_resource_label]
90
+ data_sets += data_set if data_set
91
+ page += 1
92
+ end
93
+ data_sets
94
+ end
95
+
75
96
  # Creates the base url with information collected from credentials.
76
97
  #
77
98
  # @param [Hash] opts a hash of options for building URL
@@ -93,19 +114,31 @@ module Helix
93
114
  # with the base_url to create RESTful URLs
94
115
  #
95
116
  # @param [String] url the base part of the URL to be used
96
- # @param [Hash] opts a hash of options for building URL additions
117
+ # @param [Hash] original_opts a hash of options for building URL additions
97
118
  # @return [String] The full RESTful URL string object
98
119
  def get_response(url, original_opts={})
99
120
  opts = original_opts.clone
100
121
  sig_type = opts.delete(:sig_type)
101
122
  params = opts.merge(signature: signature(sig_type, opts))
102
- response = RestClient.get(url, params: params)
103
- parse_response_by_url_format(response, url)
123
+ @response = RestClient.get(url, params: params)
124
+ parse_response_by_url_format(@response, url)
125
+ end
126
+
127
+ # Reports whether the most recent response's headers have a true :is_last_page value
128
+ #
129
+ # @return [Boolean] As above. Returns false if no such header is found,
130
+ # or if there is an explictly false value.
131
+ def last_page?
132
+ return false unless @response
133
+ return false unless @response.headers
134
+ @response.headers.has_key?(:is_last_page) and
135
+ @response.headers[:is_last_page] == "true"
104
136
  end
105
137
 
106
138
  # Fetches the signature for a specific license key.
107
139
  #
108
140
  # @param [Symbol] sig_type The type of signature required for calls.
141
+ # @param [Hash] opts allows you to overide contributor and license_id
109
142
  # @return [String] The signature needed to pass around for calls.
110
143
  def signature(sig_type, opts={})
111
144
  prepare_signature_memoization
@@ -181,6 +214,7 @@ module Helix
181
214
 
182
215
  def url_for(sig_type, opts={})
183
216
  contributor, library_id = [:contributor, :library_id].map { |key| opts[key] }
217
+ contributor ||= credentials[:contributor]
184
218
  url = "#{credentials[:site]}/api/#{sig_type}_key?licenseKey=#{credentials[:license_key]}&duration=#{SIG_DURATION}"
185
219
  url += "&contributor=#{contributor}" if contributor
186
220
  url += "&library_id=#{library_id}" if library_id
@@ -5,8 +5,8 @@ module Helix
5
5
  module ClassMethods
6
6
 
7
7
  # Used to import tracks from a URL into the Twistage system.
8
- # Doc reference: /doc/api/track/import
9
- # Doc reference: /doc/api/video/import
8
+ # API doc reference: /doc/api/track/import
9
+ # API doc reference: /doc/api/video/import
10
10
  #
11
11
  # @example
12
12
  # track = Helix::Track.import(src: "www.google.com/track.mp4",
@@ -62,9 +62,9 @@ module Helix
62
62
  end
63
63
 
64
64
  def rest_post(api_call, attrs)
65
- RestClient.log = 'helix.log' if attrs.delete(:log)
66
- content_type = url_opts_for[api_call][:content_type]
67
- content_type_hash = { content_type: "text/#{content_type}" }
65
+ RestClient.log = 'helix.log' if attrs.delete(:log)
66
+ content_type = url_opts_for[api_call][:content_type]
67
+ content_type_hash = { content_type: "text/#{content_type}" }
68
68
  RestClient.post(get_url_for(api_call, attrs),
69
69
  get_xml(attrs),
70
70
  get_params(attrs).merge(content_type_hash))
@@ -2,7 +2,9 @@ require 'helix/media'
2
2
 
3
3
  module Helix
4
4
 
5
- class Library < Media
5
+ class Library < Base
6
+
7
+ include RESTful
6
8
 
7
9
  # The class name, to be used by supporting classes. Such as Config which uses
8
10
  # this method as a way to build URLs.
@@ -1,70 +1,11 @@
1
1
  require 'helix/base'
2
2
 
3
3
  module Helix
4
- class Media < Base
5
- # Creates a new record via API and then returns an instance of that record.
6
- #
7
- # Example is using Video class since Video inherits from Base. This won't
8
- # normally be called as Helix::Base.create
9
- #
10
- # @example
11
- # Helix::Album.create({title: "My new album"})
12
- #
13
- # @param [Hash] attributes a hash containing the attributes used in the create
14
- # @return [Base] An instance of Helix::Base
15
- def self.create(attributes={})
16
- url = config.build_url(resource_label: plural_resource_label,
17
- content_type: :xml)
18
- response = RestClient.post(url, attributes.merge(signature: config.signature(:update)))
19
- attrs = Hash.from_xml(response)
20
- self.new(attributes: attrs[resource_label_sym.to_s], config: config)
21
- end
22
4
 
23
- # Finds and returns a record in instance form for a class, through
24
- # guid lookup.
25
- #
26
- # @example
27
- # video_guid = "8e0701c142ab1"
28
- # video = Helix::Video.find(video_guid)
29
- #
30
- # @param [String] guid an id in guid form.
31
- # @return [Base] An instance of Helix::Base
32
- def self.find(guid)
33
- raise ArgumentError.new("find requires a non-nil guid argument - received a nil argument.") if guid.nil?
34
- item = self.new(attributes: { guid_name => guid }, config: config)
35
- item.load
36
- end
5
+ class Media < Base
37
6
 
38
- # Deletes the record of the Helix::Base instance.
39
- #
40
- # @example
41
- # video = Helix::Video.create({title: "Some Title"})
42
- # video.destroy
43
- #
44
- # @return [String] The response from the HTTP DELETE call.
45
- def destroy
46
- url = config.build_url(content_type: :xml, guid: guid, resource_label: plural_resource_label)
47
- RestClient.delete(url, params: {signature: config.signature(:update)})
48
- end
7
+ include RESTful, Uploadable
49
8
 
50
- # Updates instance and record with attributes passed in.
51
- #
52
- # @example
53
- # video = Helix::Video.find(video_guid)
54
- # video.update({title: "My new title"})
55
- #
56
- # @param [Hash] opts a hash of attributes to update the instance with.
57
- # @return [Base] Returns an instance of the class after update.
58
- def update(original_opts={})
59
- opts = original_opts.clone
60
- RestClient.log = 'helix.log' if opts.delete(:log)
61
- memo_cfg = config
62
- url = memo_cfg.build_url(content_type: :xml,
63
- guid: guid,
64
- resource_label: plural_resource_label)
65
- params = {signature: memo_cfg.signature(:update)}.merge(resource_label_sym => opts)
66
- RestClient.put(url, params)
67
- self
68
- end
69
9
  end
10
+
70
11
  end
@@ -0,0 +1,89 @@
1
+ module Helix
2
+
3
+ # Mixed-in to ORM classes to provide basic RESTful CRUD operations.
4
+
5
+ module RESTful
6
+
7
+ # Deletes the record of the Helix::Base instance.
8
+ #
9
+ # @example
10
+ # video = Helix::Video.create({title: "Some Title"})
11
+ # video.destroy
12
+ #
13
+ # @return [String] The response from the HTTP DELETE call.
14
+ def destroy
15
+ url = config.build_url(build_url_opts)
16
+ RestClient.delete(url, params: {signature: config.signature(:update)})
17
+ end
18
+
19
+ # Updates instance and record with attributes passed in.
20
+ #
21
+ # @example
22
+ # video = Helix::Video.find(video_guid)
23
+ # video.update({title: "My new title"})
24
+ #
25
+ # @param [Hash] opts a hash of attributes to update the instance with.
26
+ # @return [Base] Returns an instance of the class after update.
27
+ def update(original_opts={})
28
+ opts = original_opts.clone
29
+ RestClient.log = 'helix.log' if opts.delete(:log)
30
+ memo_cfg = config
31
+ url = memo_cfg.build_url(build_url_opts)
32
+ params = {signature: memo_cfg.signature(:update)}.merge(resource_label_sym => opts)
33
+ RestClient.put(url, params)
34
+ self
35
+ end
36
+
37
+ private
38
+
39
+ def build_url_opts
40
+ self.class.build_url_opts.merge({guid: guid, resource_label: plural_resource_label})
41
+ end
42
+
43
+ module ClassMethods
44
+
45
+ # Creates a new record via API and then returns an instance of that record.
46
+ #
47
+ # Example is using Video class since Video inherits from Base. This won't
48
+ # normally be called as Helix::Base.create
49
+ #
50
+ # @example
51
+ # Helix::Album.create({title: "My new album"})
52
+ #
53
+ # @param [Hash] attributes a hash containing the attributes used in the create
54
+ # @return [Base] An instance of Helix::Base
55
+ def create(attributes={})
56
+ raise Helix::NoConfigurationLoaded.new if config.nil?
57
+ url = config.build_url(build_url_opts)
58
+ response = RestClient.post(url, attributes.merge(signature: config.signature(:update)))
59
+ attrs = Hash.from_xml(response)
60
+ self.new(attributes: attrs[resource_label_sym.to_s], config: config)
61
+ end
62
+
63
+ # Finds and returns a record in instance form for a class, through
64
+ # guid lookup.
65
+ #
66
+ # @example
67
+ # video_guid = "8e0701c142ab1"
68
+ # video = Helix::Video.find(video_guid)
69
+ #
70
+ # @param [String] guid an id in guid form.
71
+ # @return [Base] An instance of Helix::Base
72
+ def find(guid)
73
+ raise ArgumentError.new("find requires a non-nil guid argument - received a nil argument.") if guid.nil?
74
+ raise Helix::NoConfigurationLoaded.new if config.nil?
75
+ item = self.new(attributes: { guid_name => guid }, config: config)
76
+ item.load
77
+ end
78
+
79
+ def build_url_opts
80
+ {content_type: :xml, resource_label: plural_resource_label}
81
+ end
82
+
83
+ end
84
+
85
+ def self.included(klass); klass.extend(ClassMethods); end
86
+
87
+ end
88
+
89
+ end