apple-news 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 49d7dc6cf8af8b5a5d8cbe1506c726ab8b7f2f6c
4
- data.tar.gz: bc7c9403b332703d6c31f97804b869d83a39b298
3
+ metadata.gz: 7d6c403146c04a7a93ffe92adaa573a15dd9d551
4
+ data.tar.gz: 6f82b260da85c323757389ad47d83b843c8967e5
5
5
  SHA512:
6
- metadata.gz: 35fd32d286a50ce9e9f851d18f46f834ff63c0c5a5f3d8b5f0fd74581bdf22e27147671603b95e73a86fcc53e8ac1f9b7517c657e4d2608991bcc92eb39248a6
7
- data.tar.gz: 77d4cda118ab87d06efe10dd53f4ebcd8a9f76bbab34bda133afb627d1705c558cac62efaf9da7a2d2d19cc4ba473d50f22e7fa394ab0f441cd3342751d26007
6
+ metadata.gz: 1224e897e5dac6d57e17f6c1a022efa778e530f7bd3d794468a4af8453ec590134c6e17aa266da9f596bf263b92ea3916ccacedb0de44f508dd4b39075d38b08
7
+ data.tar.gz: 3c2f340b35ad3448708f38800db080b341e2f16053618e8bf8c9b88abf9c46eed8845b79840ad29f2bea8cf5ee4218575e2ad1e7eafedd7bc7f153631dd202eb
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 HODINKEE
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -35,10 +35,19 @@ AppleNews.config.api_key_secret = "miJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
35
35
  You can fetch the Channel information by calling:
36
36
 
37
37
  ``` ruby
38
- channel = AppleNews::Channel.current
38
+ channel = AppleNews.config.channel
39
39
  ```
40
40
 
41
- Because each channel has a separate API key, there is only ever one channel that you can fetch.
41
+ If working with multiple channels:
42
+
43
+ ```ruby
44
+ config = AppleNews::Configuration.new(
45
+ channel_id: '...',
46
+ api_key_id: '...',
47
+ api_key_secret: '...'
48
+ )
49
+ channel = config.channel
50
+ ```
42
51
 
43
52
  ### Sections
44
53
 
@@ -48,7 +57,7 @@ You can either fetch sections by their ID, or by fetching all of them through th
48
57
  section = AppleNews::Section.new(section_id)
49
58
 
50
59
  # or
51
- channel = AppleNews::Channel.current
60
+ channel = AppleNews.config.channel
52
61
  channel.default_section # for the default section
53
62
  channel.sections # for all the sections
54
63
  ```
@@ -61,11 +70,24 @@ You can fetch articles either by their ID, their channel, or their section.
61
70
  article = AppleNews::Article.new(article_id)
62
71
 
63
72
  # or
64
- channel = AppleNews::Channel.current
73
+ channel = AppleNews.config.channel
65
74
  channel.articles # all articles in the channel
66
75
  channel.default_section.articles # all articles in the default section
67
76
  ```
68
77
 
78
+ The 10 most recent articles are returned by default. To change the number or sort order, you can pass any of [the query params defined in the API docs](https://developer.apple.com/library/content/documentation/General/Conceptual/News_API_Ref/SearchArticles.html#//apple_ref/doc/uid/TP40015409-CH17-SW1). For example:
79
+
80
+ ``` ruby
81
+ # first 5 articles
82
+ channel.articles(sortDir: 'ASC', pageSize: 5)
83
+ ```
84
+
85
+ A "Read Article" API request will be made for each article to ensure that `#document` exists (the search endpoint only returns read-only attributes). If you don't need to access the document, you can opt-out of this behavior via:
86
+
87
+ ``` ruby
88
+ channel.articles(hydrate: false)
89
+ ```
90
+
69
91
  ## Submitting Articles
70
92
 
71
93
  Apple News articles are submitted as "bundles", with the article content and attached files together in one request. Because of this, we have the concept of a Document. The Document is what contains the actual article content in the Apple News JSON format. The Article encapsulates this and also includes all of the files that will be submitted along with the document.
@@ -1,37 +1,30 @@
1
1
  require 'apple-news/article/attachments'
2
2
  require 'apple-news/article/persistence'
3
+ require 'apple-news/document'
3
4
 
4
5
  module AppleNews
5
6
  class Article
6
- extend Forwardable
7
-
8
7
  include Attachments
9
8
  include Persistence
10
9
  include Resource
11
10
  include Properties
12
11
 
13
- optional_properties :is_sponsored, :is_preview, :accessory_text, :revision
12
+ optional_properties :is_sponsored, :is_preview, :accessory_text, :revision,
13
+ :maturity_rating, :is_candidate_to_be_featured
14
14
  optional_property :links, {}
15
15
 
16
- attr_reader :id, :share_url, :state
16
+ attr_reader :id, :type, :title, :share_url, :state, :warnings, :created_at, :modified_at
17
17
  attr_accessor :document
18
- def_delegator :@document, :title
19
18
 
20
- def initialize(id = nil, data = {})
21
- super(data)
19
+ def initialize(id = nil, data = {}, config = AppleNews.config)
20
+ assign_data(data)
22
21
 
23
- @resource_path = "/articles"
24
22
  @id = id
25
-
26
- document = (data[:document] || data['document'])
27
- @document = document.is_a?(AppleNews::Document) ? document : Document.new(document)
23
+ @config = config
24
+ @resource_path = '/articles'
28
25
  @files = {}
29
26
 
30
- # These are read-only properties that are not submitted to the API
31
- @share_url = data['shareUrl']
32
- @state = data['state']
33
-
34
- hydrate! if !id.nil? && data.keys.size == 0
27
+ hydrate! if id.present? && data.blank?
35
28
  end
36
29
 
37
30
  def reload
@@ -43,13 +36,17 @@ module AppleNews
43
36
 
44
37
  def hydrate!
45
38
  data = fetch_data['data']
46
-
47
- # Some special properties that need to be manually set.
48
- @document = Document.new(data.delete('document'))
49
- @share_url = data.delete('shareUrl')
50
- @state = data.delete('state')
39
+ assign_data(data)
40
+ end
41
+
42
+ def assign_data(data)
43
+ data = data.with_indifferent_access
44
+ document = data.delete(:document)
51
45
 
46
+ set_read_only_properties(data)
52
47
  load_properties(data)
48
+
49
+ @document = document.is_a?(AppleNews::Document) ? document : Document.new(document)
53
50
  end
54
51
  end
55
52
  end
@@ -5,7 +5,7 @@ module AppleNews
5
5
 
6
6
  included do
7
7
  def save!
8
- request = Request::Post.new(endpoint_url)
8
+ request = Request::Post.new(endpoint_url, config)
9
9
  request.fields = {
10
10
  'metadata' => metadata_field,
11
11
  'article.json' => document_json
@@ -27,7 +27,7 @@ module AppleNews
27
27
  alias_method :saved?, :persisted?
28
28
 
29
29
  def delete!
30
- request = Request::Delete.new(endpoint_url)
30
+ request = Request::Delete.new(endpoint_url, config)
31
31
  resp = request.call
32
32
 
33
33
  return resp['errors'] if resp.is_a?(Hash) && resp.has_key?('errors')
@@ -65,7 +65,7 @@ module AppleNews
65
65
  if persisted?
66
66
  "/articles/#{id}"
67
67
  else
68
- "/channels/#{AppleNews.config.channel_id}/articles"
68
+ "/channels/#{config.channel_id}/articles"
69
69
  end
70
70
  end
71
71
 
@@ -7,33 +7,37 @@ module AppleNews
7
7
  :default_section, :share_url
8
8
 
9
9
  def self.current
10
- self.new(AppleNews.config.channel_id)
10
+ warn 'DEPRECATION WARNING: `AppleNews::Channel.current` is deprecated. '\
11
+ 'Please use `AppleNews.config.channel` instead.'
12
+ AppleNews.config.channel
11
13
  end
12
14
 
13
- def initialize(id, data = nil)
15
+ def initialize(id, data = nil, config = AppleNews.config)
14
16
  @id = id
15
- @resource_path = "/channels"
17
+ @config = config
18
+ @resource_path = '/channels'
16
19
 
17
20
  data.nil? ? hydrate! : set_read_only_properties(data)
18
21
  end
19
22
 
20
23
  def default_section
21
- Section.new(section_link_id('defaultSection'))
24
+ Section.new(section_link_id('defaultSection'), nil, config)
22
25
  end
23
26
 
24
27
  def sections
25
- request = Request::Get.new("/channels/#{id}/sections")
26
- resp = request.call
28
+ resp = get_request("/channels/#{id}/sections")
27
29
  resp['data'].map do |section|
28
- Section.new(section['id'], section)
30
+ Section.new(section['id'], section, config)
29
31
  end
30
32
  end
31
33
 
32
34
  def articles(params = {})
33
- request = Request::Get.new("/channels/#{id}/articles")
34
- resp = request.call(params)
35
+ params = params.with_indifferent_access
36
+ hydrate = params.delete(:hydrate)
37
+ resp = get_request("/channels/#{id}/articles", params)
35
38
  resp['data'].map do |article|
36
- Article.new(article['id'])
39
+ data = hydrate == false ? article : {}
40
+ Article.new(article['id'], data, config)
37
41
  end
38
42
  end
39
43
  end
@@ -1,12 +1,16 @@
1
1
  module AppleNews
2
2
  class Configuration
3
3
  attr_accessor :channel_id, :api_key_id, :api_key_secret, :api_base
4
-
5
- def initialize
6
- @channel_id = nil
7
- @api_key_id = nil
8
- @api_key_secret = nil
9
- @api_base = 'https://news-api.apple.com'
4
+
5
+ def initialize(attributes = {})
6
+ @channel_id = attributes[:channel_id]
7
+ @api_key_id = attributes[:api_key_id]
8
+ @api_key_secret = attributes[:api_key_secret]
9
+ @api_base = attributes[:api_base] || 'https://news-api.apple.com'
10
+ end
11
+
12
+ def channel
13
+ AppleNews::Channel.new(channel_id, nil, self)
10
14
  end
11
15
  end
12
16
  end
@@ -9,8 +9,9 @@ module AppleNews
9
9
  def load_properties(opts)
10
10
  opts = ActiveSupport::HashWithIndifferentAccess.new(opts || {})
11
11
  self.class.properties.each do |prop, settings|
12
+ camelized_prop = prop.to_s.camelize(:lower)
12
13
  val = if !settings[:klass].nil?
13
- assigned_val = opts.fetch(prop, settings[:default])
14
+ assigned_val = opts.fetch(camelized_prop, settings[:default])
14
15
 
15
16
  if settings[:default].is_a?(Array)
16
17
  assigned_val.map { |v|
@@ -26,7 +27,7 @@ module AppleNews
26
27
  assigned_val.nil? ? nil : settings[:klass].send(settings[:init_method], assigned_val)
27
28
  end
28
29
  else
29
- opts.fetch(prop, settings[:default])
30
+ opts.fetch(camelized_prop, settings[:default])
30
31
  end
31
32
 
32
33
  instance_variable_set "@#{prop}", val
@@ -3,8 +3,8 @@ module AppleNews
3
3
  class Delete
4
4
  attr_reader :url
5
5
 
6
- def initialize(url)
7
- @config = AppleNews.config
6
+ def initialize(url, config = AppleNews.config)
7
+ @config = config
8
8
  @url = URI::parse(File.join(@config.api_base, url))
9
9
  end
10
10
 
@@ -20,7 +20,7 @@ module AppleNews
20
20
  private
21
21
 
22
22
  def headers
23
- security = AppleNews::Security.new('DELETE', @url.to_s)
23
+ security = AppleNews::Security.new('DELETE', @url.to_s, @config)
24
24
  { 'Authorization' => security.authorization }
25
25
  end
26
26
  end
@@ -3,8 +3,8 @@ module AppleNews
3
3
  class Get
4
4
  attr_reader :url
5
5
 
6
- def initialize(url)
7
- @config = AppleNews.config
6
+ def initialize(url, config = AppleNews.config)
7
+ @config = config
8
8
  @url = URI::parse(File.join(@config.api_base, url))
9
9
  end
10
10
 
@@ -20,7 +20,7 @@ module AppleNews
20
20
  private
21
21
 
22
22
  def headers
23
- security = AppleNews::Security.new('GET', @url.to_s)
23
+ security = AppleNews::Security.new('GET', @url.to_s, @config)
24
24
  { 'Authorization' => security.authorization }
25
25
  end
26
26
  end
@@ -4,8 +4,8 @@ module AppleNews
4
4
  attr_reader :url
5
5
  attr_accessor :fields
6
6
 
7
- def initialize(url)
8
- @config = AppleNews.config
7
+ def initialize(url, config = AppleNews.config)
8
+ @config = config
9
9
  @url = URI::parse(File.join(@config.api_base, url))
10
10
  @fields = {}
11
11
  end
@@ -42,7 +42,7 @@ module AppleNews
42
42
  end
43
43
 
44
44
  def authorization
45
- security = AppleNews::Security.new('POST', @url)
45
+ security = AppleNews::Security.new('POST', @url, @config)
46
46
  security.content_type = "multipart/form-data; boundary=#{Net::HTTP::Post::Multipart::DEFAULT_BOUNDARY}"
47
47
  security.content_body = content_body
48
48
 
@@ -3,6 +3,8 @@ module AppleNews
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
+ attr_accessor :config
7
+
6
8
  def update_with_data(data)
7
9
  load_properties(data)
8
10
  end
@@ -11,6 +13,10 @@ module AppleNews
11
13
  File.join(@resource_path, id)
12
14
  end
13
15
 
16
+ def get_request(path, params = {})
17
+ AppleNews::Request::Get.new(path, config).call(params)
18
+ end
19
+
14
20
  private
15
21
 
16
22
  def hydrate!
@@ -22,13 +28,12 @@ module AppleNews
22
28
  end
23
29
 
24
30
  def fetch_data
25
- request = AppleNews::Request::Get.new(resource_url)
26
- request.call
31
+ get_request(resource_url)
27
32
  end
28
33
 
29
34
  def set_read_only_properties(data)
30
35
  data.each do |k, v|
31
- instance_variable_set("@#{k.underscore}", v)
36
+ instance_variable_set("@#{k.to_s.underscore}", v)
32
37
  end
33
38
  end
34
39
  end
@@ -5,22 +5,25 @@ module AppleNews
5
5
 
6
6
  attr_reader :id, :type, :name, :is_default, :links, :created_at, :modified_at, :share_url
7
7
 
8
- def initialize(id, data = nil)
8
+ def initialize(id, data = nil, config = AppleNews.config)
9
9
  @id = id
10
- @resource_path = "/sections"
10
+ @config = config
11
+ @resource_path = '/sections'
11
12
 
12
13
  data.nil? ? hydrate! : set_read_only_properties(data)
13
14
  end
14
15
 
15
16
  def channel
16
- Channel.new(channel_link_id('channel'))
17
+ Channel.new(channel_link_id('channel'), nil, config)
17
18
  end
18
19
 
19
20
  def articles(params = {})
20
- request = Request::Get.new("/sections/#{id}/articles")
21
- resp = request.call(params)
21
+ params = params.with_indifferent_access
22
+ hydrate = params.delete(:hydrate)
23
+ resp = get_request("/sections/#{id}/articles", params)
22
24
  resp['data'].map do |article|
23
- Article.new(article['id'])
25
+ data = hydrate == false ? article : {}
26
+ Article.new(article['id'], data, config)
24
27
  end
25
28
  end
26
29
  end
@@ -1,12 +1,14 @@
1
+ require 'base64'
2
+ require 'openssl'
3
+
1
4
  module AppleNews
2
5
  class Security
3
6
  attr_accessor :method, :url, :content_type, :content_body
4
7
 
5
- def initialize(method, url)
6
- @config = AppleNews.config
7
-
8
+ def initialize(method, url, config = AppleNews.config)
8
9
  @method = method.upcase
9
10
  @url = url
11
+ @config = config
10
12
  @date = Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
11
13
  @content_type = nil
12
14
  @content_body = nil
@@ -1,3 +1,3 @@
1
1
  module AppleNews
2
- VERSION = "0.4.2"
2
+ VERSION = "0.5.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apple-news
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan LeFevre
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-12-09 00:00:00.000000000 Z
11
+ date: 2017-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -92,6 +92,7 @@ files:
92
92
  - ".rspec"
93
93
  - ".travis.yml"
94
94
  - Gemfile
95
+ - LICENSE
95
96
  - README.md
96
97
  - Rakefile
97
98
  - apple-news.gemspec