apple-news 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +44 -20
- data/lib/apple-news.rb +2 -2
- data/lib/apple-news/addition.rb +21 -0
- data/lib/apple-news/additions/base.rb +1 -1
- data/lib/apple-news/animation.rb +21 -0
- data/lib/apple-news/animations/base.rb +1 -1
- data/lib/apple-news/article.rb +29 -17
- data/lib/apple-news/{document → article}/attachments.rb +1 -1
- data/lib/apple-news/article/persistence.rb +63 -0
- data/lib/apple-news/behavior.rb +21 -0
- data/lib/apple-news/behaviors/base.rb +1 -1
- data/lib/apple-news/channel.rb +4 -4
- data/lib/apple-news/component.rb +4 -0
- data/lib/apple-news/components/base.rb +4 -2
- data/lib/apple-news/components/chapter.rb +1 -1
- data/lib/apple-news/components/container.rb +1 -1
- data/lib/apple-news/components/divider.rb +1 -1
- data/lib/apple-news/components/gallery.rb +1 -1
- data/lib/apple-news/components/mosaic.rb +1 -1
- data/lib/apple-news/components/section.rb +1 -1
- data/lib/apple-news/components/text.rb +7 -2
- data/lib/apple-news/document.rb +17 -14
- data/lib/apple-news/properties.rb +26 -9
- data/lib/apple-news/properties/advertising_settings.rb +4 -1
- data/lib/apple-news/properties/caption_descriptor.rb +3 -1
- data/lib/apple-news/requests/delete.rb +28 -0
- data/lib/apple-news/requests/post.rb +1 -0
- data/lib/apple-news/resource.rb +16 -5
- data/lib/apple-news/scene.rb +21 -0
- data/lib/apple-news/scenes/base.rb +1 -1
- data/lib/apple-news/section.rb +4 -4
- data/lib/apple-news/version.rb +1 -1
- metadata +5 -5
- data/lib/apple-news/document/metadata.rb +0 -43
- data/lib/apple-news/document/persistence.rb +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d4c2accd3a83c76997106e65005ca440498773b
|
4
|
+
data.tar.gz: f10b56d9b207b1f495b8cecd7dbc8921e9301077
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ab67e0d195a10ed907963461796342f0d2cbee21a41afc230d7077e6422502d162e7bf0c169c05aecb9cc570f026c725a8557bb776abdfec8ef78dcc14ddd00
|
7
|
+
data.tar.gz: 856cc6fab4feae7ea0cafc6555be23406f3315a61eada4fa3434af9a340ea18cc38add94ddd4b324a6d7daeb1a8068455362d79c17aeee196bf9c82d83700de0
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
A fully featured gem for building Apple News documents and interfacing with the Apple News API.
|
4
4
|
|
5
|
-
**NOTE:** this is very much a work in progress. There
|
5
|
+
**NOTE:** this is very much a work in progress. There will probably be bugs, but for the most part, everything should be working.
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
@@ -70,27 +70,27 @@ channel.default_section.articles # all articles in the default section
|
|
70
70
|
|
71
71
|
## Submitting Articles
|
72
72
|
|
73
|
-
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
|
73
|
+
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.
|
74
74
|
|
75
|
-
### Building
|
75
|
+
### Building Documents
|
76
76
|
|
77
|
-
|
77
|
+
Documents are built using the `AppleNews::Document` class. All documents must have an identifier (a string generated by you to determine article uniqueness, not the ID returned from the Apple News API), title, layout, components, and a default component text style.
|
78
78
|
|
79
79
|
In order to maintain idiomatic Ruby, all properties are accessed/set via the underscore version of the actual Apple News API property. For example, `componentTextStyles` becomes `component_text_styles`.
|
80
80
|
|
81
81
|
``` ruby
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
82
|
+
document = AppleNews::Document.new
|
83
|
+
document.identifier = "1234"
|
84
|
+
document.title = "Test Article"
|
85
|
+
document.layout = AppleNews::Layout.new(columns: 1, width: 1024)
|
86
|
+
document.component_text_styles[:default] = AppleNews::Style::ComponentText.new(
|
87
87
|
font_name: 'Georgia',
|
88
88
|
font_size: 14,
|
89
89
|
text_color: '#000000'
|
90
90
|
)
|
91
91
|
|
92
|
-
|
93
|
-
|
92
|
+
document.components << AppleNews::Component::Heading.new(text: "Test Article")
|
93
|
+
document.components << AppleNews::Component::Body.new(text: "Just testing out this Ruby gem!")
|
94
94
|
```
|
95
95
|
|
96
96
|
Every component, style, property, etc. as defined by the [API documentation](https://developer.apple.com/library/ios/documentation/General/Conceptual/Apple_News_Format_Ref/index.html) has its own class. Each property can be set either by the constructor, or by calling the accessor method on the object. For example:
|
@@ -104,28 +104,52 @@ component = AppleNews::Component::Instagram.new
|
|
104
104
|
component.url = "https://www.instagram.com/p/BB7mr0hsS4U/"
|
105
105
|
```
|
106
106
|
|
107
|
-
### Creating
|
107
|
+
### Creating an Article
|
108
108
|
|
109
|
-
|
109
|
+
An article must have a document. Once it's created, you can add files to the article bundle.
|
110
110
|
|
111
111
|
``` ruby
|
112
|
-
|
113
|
-
|
112
|
+
article = AppleNews::Article.new(nil, document: document)
|
113
|
+
article.is_preview = true
|
114
114
|
|
115
115
|
# There are 3 different ways you can add a file to the document
|
116
|
-
|
117
|
-
|
118
|
-
|
116
|
+
article.add_file(File.new("/path/to/image.jpg"))
|
117
|
+
article.add_file_at_path("/path/to/image.jpg")
|
118
|
+
article.add_string_as_file("image.jpg", image_contents, "image/jpeg")
|
119
119
|
```
|
120
120
|
|
121
|
-
### Saving
|
121
|
+
### Saving an Article
|
122
122
|
|
123
123
|
Once you have your document built, you can submit it to the API.
|
124
124
|
|
125
125
|
```
|
126
|
-
|
126
|
+
article.save!
|
127
127
|
```
|
128
128
|
|
129
|
+
It will return `true` if saving succeeds, otherwise it will return an array of errors as provided by the API.
|
130
|
+
|
131
|
+
### Updating an Article
|
132
|
+
|
133
|
+
Updating an article works the same as creating an article.
|
134
|
+
|
135
|
+
``` ruby
|
136
|
+
article = AppleNews::Article.new("25c4666a-26d9-48c0-88c1-d8c84fa94ecd")
|
137
|
+
article.document.title = "New Title!"
|
138
|
+
article.is_preview = false
|
139
|
+
article.save!
|
140
|
+
```
|
141
|
+
|
142
|
+
## Deleting Articles
|
143
|
+
|
144
|
+
You can easily delete articles once they're fetched.
|
145
|
+
|
146
|
+
``` ruby
|
147
|
+
article = AppleNews::Article.new("25c4666a-26d9-48c0-88c1-d8c84fa94ecd")
|
148
|
+
article.delete!
|
149
|
+
```
|
150
|
+
|
151
|
+
This will return true when successful, otherwise it will return an array of errors as provided by the API.
|
152
|
+
|
129
153
|
## Development
|
130
154
|
|
131
155
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/apple-news.rb
CHANGED
@@ -14,19 +14,19 @@ require "apple-news/properties"
|
|
14
14
|
require "apple-news/addition"
|
15
15
|
require "apple-news/animation"
|
16
16
|
require "apple-news/behavior"
|
17
|
-
require "apple-news/component"
|
18
17
|
require "apple-news/component_layout"
|
19
18
|
require "apple-news/layout"
|
20
19
|
require "apple-news/metadata"
|
21
20
|
require "apple-news/property"
|
22
21
|
require "apple-news/scene"
|
23
22
|
require "apple-news/style"
|
23
|
+
require "apple-news/component"
|
24
24
|
|
25
25
|
require "apple-news/resource"
|
26
26
|
require "apple-news/links"
|
27
27
|
require "apple-news/configuration"
|
28
|
-
require "apple-news/document"
|
29
28
|
require "apple-news/article"
|
29
|
+
require "apple-news/document"
|
30
30
|
require "apple-news/channel"
|
31
31
|
require "apple-news/request"
|
32
32
|
require "apple-news/section"
|
data/lib/apple-news/addition.rb
CHANGED
@@ -3,5 +3,26 @@ Dir["#{File.dirname(__FILE__)}/additions/*.rb"].each { |path| require path }
|
|
3
3
|
|
4
4
|
module AppleNews
|
5
5
|
module Addition
|
6
|
+
extend self
|
7
|
+
|
8
|
+
def factory(data)
|
9
|
+
return if data.nil?
|
10
|
+
|
11
|
+
additions.each do |addition|
|
12
|
+
if addition.type == data[:type]
|
13
|
+
return addition.new(data)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def additions
|
23
|
+
@additions ||= self.constants.
|
24
|
+
map { |const| self.const_get(const) }.
|
25
|
+
select { |const| const.name.demodulize != "Base" && const.is_a?(Class) }
|
26
|
+
end
|
6
27
|
end
|
7
28
|
end
|
data/lib/apple-news/animation.rb
CHANGED
@@ -3,5 +3,26 @@ Dir["#{File.dirname(__FILE__)}/animations/*.rb"].each { |path| require path }
|
|
3
3
|
|
4
4
|
module AppleNews
|
5
5
|
module Animation
|
6
|
+
extend self
|
7
|
+
|
8
|
+
def factory(data)
|
9
|
+
return if data.nil?
|
10
|
+
|
11
|
+
animations.each do |animation|
|
12
|
+
if animation.type == data[:type]
|
13
|
+
return animation.new(data)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def animations
|
23
|
+
@animations ||= self.constants.
|
24
|
+
map { |const| self.const_get(const) }.
|
25
|
+
select { |const| const.name.demodulize != "Base" && const.is_a?(Class) }
|
26
|
+
end
|
6
27
|
end
|
7
28
|
end
|
@@ -6,7 +6,7 @@ module AppleNews
|
|
6
6
|
optional_property :user_controllable
|
7
7
|
|
8
8
|
def self.type(val = nil)
|
9
|
-
val.nil? ? _required_property_map[:type] : required_property(:type, val)
|
9
|
+
val.nil? ? _required_property_map[:type][:default] : required_property(:type, val)
|
10
10
|
end
|
11
11
|
|
12
12
|
def type
|
data/lib/apple-news/article.rb
CHANGED
@@ -1,33 +1,45 @@
|
|
1
|
+
require 'apple-news/article/attachments'
|
2
|
+
require 'apple-news/article/persistence'
|
3
|
+
|
1
4
|
module AppleNews
|
2
5
|
class Article
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
include Attachments
|
9
|
+
include Persistence
|
3
10
|
include Resource
|
4
11
|
include Properties
|
5
12
|
|
6
|
-
|
13
|
+
optional_properties :is_sponsored, :is_preview, :accessory_text, :revision
|
14
|
+
optional_property :links, {}
|
7
15
|
|
8
|
-
|
9
|
-
|
10
|
-
|
16
|
+
attr_reader :id
|
17
|
+
attr_accessor :document
|
18
|
+
def_delegator :@document, :title
|
11
19
|
|
12
|
-
|
13
|
-
|
20
|
+
def initialize(id = nil, data = {})
|
21
|
+
super(data)
|
14
22
|
|
15
|
-
|
16
|
-
|
23
|
+
@resource_path = "/articles"
|
24
|
+
@id = id
|
17
25
|
|
18
|
-
|
19
|
-
|
26
|
+
document = (data[:document] || data['document'])
|
27
|
+
@document = document.is_a?(AppleNews::Document) ? document : Document.new(document)
|
28
|
+
@files = {}
|
20
29
|
|
21
|
-
|
22
|
-
@
|
23
|
-
@
|
30
|
+
# These are read-only properties that are not submitted to the API
|
31
|
+
@share_url = data['shareUrl']
|
32
|
+
@state = data['state']
|
24
33
|
|
25
|
-
hydrate! if !id.nil? &&
|
34
|
+
hydrate! if !id.nil? && data.keys.size == 0
|
26
35
|
end
|
27
36
|
|
28
|
-
|
29
|
-
|
37
|
+
private
|
38
|
+
|
39
|
+
def hydrate!
|
40
|
+
data = fetch_data['data']
|
41
|
+
@document = Document.new(data.delete('document'))
|
42
|
+
load_properties(data)
|
30
43
|
end
|
31
|
-
alias_method :saved?, :persisted?
|
32
44
|
end
|
33
45
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module AppleNews
|
2
|
+
class Article
|
3
|
+
module Persistence
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
def save!
|
8
|
+
request = Request::Post.new(endpoint_url)
|
9
|
+
request.fields = {
|
10
|
+
'metadata' => metadata_field,
|
11
|
+
'article.json' => document_json
|
12
|
+
}.merge(@files)
|
13
|
+
|
14
|
+
resp = request.call
|
15
|
+
|
16
|
+
return resp['errors'] if resp.has_key?('errors')
|
17
|
+
|
18
|
+
@id = resp['data']['id']
|
19
|
+
load_properties(resp['data'])
|
20
|
+
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def persisted?
|
25
|
+
!@id.nil?
|
26
|
+
end
|
27
|
+
alias_method :saved?, :persisted?
|
28
|
+
|
29
|
+
def delete!
|
30
|
+
request = Request::Delete.new(endpoint_url)
|
31
|
+
resp = request.call
|
32
|
+
|
33
|
+
return resp['errors'] if resp.is_a?(Hash) && resp.has_key?('errors')
|
34
|
+
@id = nil
|
35
|
+
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def endpoint_url
|
42
|
+
if persisted?
|
43
|
+
"/articles/#{id}"
|
44
|
+
else
|
45
|
+
"/channels/#{AppleNews.config.channel_id}/articles"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def metadata_field
|
50
|
+
JSON.dump({ data: self.as_json })
|
51
|
+
end
|
52
|
+
|
53
|
+
def document_json
|
54
|
+
UploadIO.new(
|
55
|
+
StringIO.new(JSON.dump(document.as_json)),
|
56
|
+
"application/json",
|
57
|
+
"article.json"
|
58
|
+
)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/apple-news/behavior.rb
CHANGED
@@ -3,5 +3,26 @@ Dir["#{File.dirname(__FILE__)}/behaviors/*.rb"].each { |path| require path }
|
|
3
3
|
|
4
4
|
module AppleNews
|
5
5
|
module Behavior
|
6
|
+
extend self
|
7
|
+
|
8
|
+
def factory(data)
|
9
|
+
return if data.nil?
|
10
|
+
|
11
|
+
behaviors.each do |behavior|
|
12
|
+
if behavior.type == data[:type]
|
13
|
+
return behavior.new(data)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def behaviors
|
23
|
+
@behaviors ||= self.constants.
|
24
|
+
map { |const| self.const_get(const) }.
|
25
|
+
select { |const| const.name.demodulize != "Base" && const.is_a?(Class) }
|
26
|
+
end
|
6
27
|
end
|
7
28
|
end
|
data/lib/apple-news/channel.rb
CHANGED
@@ -4,7 +4,7 @@ module AppleNews
|
|
4
4
|
include Links
|
5
5
|
|
6
6
|
attr_reader :id, :type, :name, :website, :links, :created_at, :modified_at,
|
7
|
-
:default_section
|
7
|
+
:default_section, :share_url
|
8
8
|
|
9
9
|
def self.current
|
10
10
|
self.new(AppleNews.config.channel_id)
|
@@ -12,9 +12,9 @@ module AppleNews
|
|
12
12
|
|
13
13
|
def initialize(id, data = nil)
|
14
14
|
@id = id
|
15
|
-
@
|
15
|
+
@resource_path = "/channels"
|
16
16
|
|
17
|
-
data.nil? ? hydrate! :
|
17
|
+
data.nil? ? hydrate! : set_read_only_properties(data)
|
18
18
|
end
|
19
19
|
|
20
20
|
def default_section
|
@@ -33,7 +33,7 @@ module AppleNews
|
|
33
33
|
request = Request::Get.new("/channels/#{id}/articles")
|
34
34
|
resp = request.call(params)
|
35
35
|
resp['data'].map do |article|
|
36
|
-
Article.new(article['id']
|
36
|
+
Article.new(article['id'])
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
data/lib/apple-news/component.rb
CHANGED
@@ -3,10 +3,12 @@ module AppleNews
|
|
3
3
|
class Base
|
4
4
|
include Properties
|
5
5
|
|
6
|
-
|
6
|
+
optional_property :identifier
|
7
|
+
optional_property :layout, nil, ComponentLayout
|
8
|
+
optional_property :style, nil, Style::Component
|
7
9
|
|
8
10
|
def self.role(val = nil)
|
9
|
-
val.nil? ? _required_property_map[:role] : required_property(:role, val)
|
11
|
+
val.nil? ? _required_property_map[:role][:default] : required_property(:role, val)
|
10
12
|
end
|
11
13
|
|
12
14
|
def role
|
@@ -5,8 +5,13 @@ module AppleNews
|
|
5
5
|
|
6
6
|
included do
|
7
7
|
required_property :text
|
8
|
-
|
9
|
-
|
8
|
+
optional_property :format
|
9
|
+
|
10
|
+
optional_property :anchor, nil, Property::Anchor
|
11
|
+
optional_property :animation, nil, Animation, :factory
|
12
|
+
optional_property :behavior, nil, Behavior, :factory
|
13
|
+
optional_property :inline_text_styles, [], Style::InlineText
|
14
|
+
optional_property :text_style, nil, Style::Text
|
10
15
|
end
|
11
16
|
end
|
12
17
|
end
|
data/lib/apple-news/document.rb
CHANGED
@@ -1,20 +1,23 @@
|
|
1
|
-
require 'apple-news/document/attachments'
|
2
|
-
require 'apple-news/document/metadata'
|
3
|
-
require 'apple-news/document/persistence'
|
4
|
-
|
5
1
|
module AppleNews
|
6
2
|
class Document
|
7
|
-
include
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
include Properties
|
4
|
+
|
5
|
+
attr_accessor :id
|
6
|
+
|
7
|
+
required_properties :identifier, :title
|
8
|
+
required_property :layout, nil, Layout
|
9
|
+
required_property :components, [], Component, :factory
|
10
|
+
required_property :component_text_styles, {}, Style::ComponentText
|
11
11
|
|
12
|
-
|
12
|
+
required_property :version, "1.1"
|
13
|
+
required_property :language, "en"
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
optional_property :advertising_settings, nil, Property::AdvertisingSettings
|
16
|
+
optional_property :metadata, nil, Metadata
|
17
|
+
optional_property :document_style, nil, Style::Document
|
18
|
+
optional_property :text_styles, {}, Style::Text
|
19
|
+
optional_property :component_layouts, {}, ComponentLayout
|
20
|
+
optional_property :component_styles, {}, Style::Component
|
21
|
+
optional_property :subtitle
|
19
22
|
end
|
20
23
|
end
|
@@ -3,11 +3,26 @@ module AppleNews
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
def initialize(opts = nil)
|
6
|
-
if !opts.nil?
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
load_properties(opts) if !opts.nil?
|
7
|
+
end
|
8
|
+
|
9
|
+
def load_properties(opts)
|
10
|
+
opts = ActiveSupport::HashWithIndifferentAccess.new(opts)
|
11
|
+
self.class.properties.each do |prop, settings|
|
12
|
+
val = if !settings[:klass].nil?
|
13
|
+
assigned_val = opts.fetch(prop, settings[:default])
|
14
|
+
if settings[:default].is_a?(Array)
|
15
|
+
assigned_val.map { |v| settings[:klass].send(settings[:init_method], v) }
|
16
|
+
elsif settings[:default].is_a?(Hash)
|
17
|
+
Hash[assigned_val.map { |k, v| [k, settings[:klass].send(settings[:init_method], v)]}]
|
18
|
+
else
|
19
|
+
assigned_val.nil? ? nil : settings[:klass].send(settings[:init_method], assigned_val)
|
20
|
+
end
|
21
|
+
else
|
22
|
+
opts.fetch(prop, settings[:default])
|
10
23
|
end
|
24
|
+
|
25
|
+
instance_variable_set "@#{prop}", val
|
11
26
|
end
|
12
27
|
end
|
13
28
|
|
@@ -40,7 +55,9 @@ module AppleNews
|
|
40
55
|
elsif send(key).is_a?(Array)
|
41
56
|
send(key).map(&:as_json)
|
42
57
|
elsif send(key).is_a?(Hash)
|
43
|
-
Hash[send(key).map {|k, v|
|
58
|
+
Hash[send(key).map {|k, v|
|
59
|
+
[k.to_s, v.respond_to?(:as_json) ? v.as_json : v]
|
60
|
+
}]
|
44
61
|
else
|
45
62
|
send(key)
|
46
63
|
end
|
@@ -61,8 +78,8 @@ module AppleNews
|
|
61
78
|
args.each { |arg| required_property(arg) }
|
62
79
|
end
|
63
80
|
|
64
|
-
def required_property(name, default = nil)
|
65
|
-
_required_property_map[name] = default
|
81
|
+
def required_property(name, default = nil, klass = nil, init_method = :new)
|
82
|
+
_required_property_map[name] = { default: default, klass: klass, init_method: init_method }
|
66
83
|
attr_accessor name
|
67
84
|
end
|
68
85
|
|
@@ -70,8 +87,8 @@ module AppleNews
|
|
70
87
|
args.each { |arg| optional_property(arg) }
|
71
88
|
end
|
72
89
|
|
73
|
-
def optional_property(name, default = nil)
|
74
|
-
_optional_property_map[name] = default
|
90
|
+
def optional_property(name, default = nil, klass = nil, init_method = :new)
|
91
|
+
_optional_property_map[name] = { default: default, klass: klass, init_method: init_method }
|
75
92
|
attr_accessor name
|
76
93
|
end
|
77
94
|
|
@@ -1,7 +1,10 @@
|
|
1
|
+
require 'apple-news/properties/advertising_layout'
|
2
|
+
|
1
3
|
module AppleNews
|
2
4
|
module Property
|
3
5
|
class AdvertisingSettings < Base
|
4
|
-
|
6
|
+
optional_property :frequency
|
7
|
+
optional_property :layout, nil, Property::AdvertisingLayout
|
5
8
|
end
|
6
9
|
end
|
7
10
|
end
|
@@ -2,7 +2,9 @@ module AppleNews
|
|
2
2
|
module Property
|
3
3
|
class CaptionDescriptor < Base
|
4
4
|
required_property :text
|
5
|
-
optional_properties :text_style, :format
|
5
|
+
optional_properties :text_style, :format
|
6
|
+
optional_property :inline_text_styles, []
|
7
|
+
optional_property :additions, []
|
6
8
|
end
|
7
9
|
end
|
8
10
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module AppleNews
|
2
|
+
module Request
|
3
|
+
class Delete
|
4
|
+
attr_reader :url
|
5
|
+
|
6
|
+
def initialize(url)
|
7
|
+
@config = AppleNews.config
|
8
|
+
@url = URI::parse(File.join(@config.api_base, url))
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(params = {})
|
12
|
+
http = Net::HTTP.new(@url.hostname, @url.port)
|
13
|
+
http.use_ssl = true
|
14
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
15
|
+
|
16
|
+
res = http.delete(@url, headers)
|
17
|
+
res.code == '204' ? true : JSON.parse(res.body)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def headers
|
23
|
+
security = AppleNews::Security.new('DELETE', @url.to_s)
|
24
|
+
{ 'Authorization' => security.authorization }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/apple-news/resource.rb
CHANGED
@@ -4,18 +4,29 @@ module AppleNews
|
|
4
4
|
|
5
5
|
included do
|
6
6
|
def update_with_data(data)
|
7
|
-
|
7
|
+
load_properties(data)
|
8
|
+
end
|
9
|
+
|
10
|
+
def resource_url
|
11
|
+
File.join(@resource_path, id)
|
8
12
|
end
|
9
13
|
|
10
14
|
private
|
11
15
|
|
12
16
|
def hydrate!
|
13
|
-
|
14
|
-
|
15
|
-
|
17
|
+
if respond_to?(:load_properties)
|
18
|
+
load_properties(fetch_data['data'])
|
19
|
+
else
|
20
|
+
set_read_only_properties(fetch_data['data'])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def fetch_data
|
25
|
+
request = AppleNews::Request::Get.new(resource_url)
|
26
|
+
request.call
|
16
27
|
end
|
17
28
|
|
18
|
-
def
|
29
|
+
def set_read_only_properties(data)
|
19
30
|
data.each do |k, v|
|
20
31
|
instance_variable_set("@#{k.underscore}", v)
|
21
32
|
end
|
data/lib/apple-news/scene.rb
CHANGED
@@ -3,5 +3,26 @@ Dir["#{File.dirname(__FILE__)}/scenes/*.rb"].each { |path| require path }
|
|
3
3
|
|
4
4
|
module AppleNews
|
5
5
|
module Scene
|
6
|
+
extend self
|
7
|
+
|
8
|
+
def factory(data)
|
9
|
+
return if data.nil?
|
10
|
+
|
11
|
+
scenes.each do |scene|
|
12
|
+
if scene.type == data[:type]
|
13
|
+
return scene.new(data)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def scenes
|
23
|
+
@scenes ||= self.constants.
|
24
|
+
map { |const| self.const_get(const) }.
|
25
|
+
select { |const| const.name.demodulize != "Base" && const.is_a?(Class) }
|
26
|
+
end
|
6
27
|
end
|
7
28
|
end
|
data/lib/apple-news/section.rb
CHANGED
@@ -3,13 +3,13 @@ module AppleNews
|
|
3
3
|
include Resource
|
4
4
|
include Links
|
5
5
|
|
6
|
-
attr_reader :id, :type, :name, :is_default, :links, :created_at, :modified_at
|
6
|
+
attr_reader :id, :type, :name, :is_default, :links, :created_at, :modified_at, :share_url
|
7
7
|
|
8
8
|
def initialize(id, data = nil)
|
9
9
|
@id = id
|
10
|
-
@
|
10
|
+
@resource_path = "/sections"
|
11
11
|
|
12
|
-
data.nil? ? hydrate! :
|
12
|
+
data.nil? ? hydrate! : set_read_only_properties(data)
|
13
13
|
end
|
14
14
|
|
15
15
|
def channel
|
@@ -20,7 +20,7 @@ module AppleNews
|
|
20
20
|
request = Request::Get.new("/sections/#{id}/articles")
|
21
21
|
resp = request.call(params)
|
22
22
|
resp['data'].map do |article|
|
23
|
-
Article.new(article['id']
|
23
|
+
Article.new(article['id'])
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
data/lib/apple-news/version.rb
CHANGED
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
|
+
version: 0.2.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-04-
|
11
|
+
date: 2016-04-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -108,6 +108,8 @@ files:
|
|
108
108
|
- lib/apple-news/animations/move_in.rb
|
109
109
|
- lib/apple-news/animations/scale_fade.rb
|
110
110
|
- lib/apple-news/article.rb
|
111
|
+
- lib/apple-news/article/attachments.rb
|
112
|
+
- lib/apple-news/article/persistence.rb
|
111
113
|
- lib/apple-news/behavior.rb
|
112
114
|
- lib/apple-news/behaviors/background_motion.rb
|
113
115
|
- lib/apple-news/behaviors/background_parallax.rb
|
@@ -154,9 +156,6 @@ files:
|
|
154
156
|
- lib/apple-news/components/video.rb
|
155
157
|
- lib/apple-news/configuration.rb
|
156
158
|
- lib/apple-news/document.rb
|
157
|
-
- lib/apple-news/document/attachments.rb
|
158
|
-
- lib/apple-news/document/metadata.rb
|
159
|
-
- lib/apple-news/document/persistence.rb
|
160
159
|
- lib/apple-news/layout.rb
|
161
160
|
- lib/apple-news/links.rb
|
162
161
|
- lib/apple-news/metadata.rb
|
@@ -174,6 +173,7 @@ files:
|
|
174
173
|
- lib/apple-news/properties/offset.rb
|
175
174
|
- lib/apple-news/property.rb
|
176
175
|
- lib/apple-news/request.rb
|
176
|
+
- lib/apple-news/requests/delete.rb
|
177
177
|
- lib/apple-news/requests/get.rb
|
178
178
|
- lib/apple-news/requests/post.rb
|
179
179
|
- lib/apple-news/resource.rb
|
@@ -1,43 +0,0 @@
|
|
1
|
-
module AppleNews
|
2
|
-
class Document
|
3
|
-
module Metadata
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
def is_sponsored?
|
8
|
-
@metadata['isSponsored']
|
9
|
-
end
|
10
|
-
alias_method :sponsored?, :is_sponsored?
|
11
|
-
|
12
|
-
def is_sponsored=(val)
|
13
|
-
@metadata['isSponsored'] = val
|
14
|
-
end
|
15
|
-
|
16
|
-
def is_preview?
|
17
|
-
@metadata['isPreview']
|
18
|
-
end
|
19
|
-
alias_method :preview?, :is_preview?
|
20
|
-
|
21
|
-
def is_preview=(val)
|
22
|
-
@metadata['isPreview'] = val
|
23
|
-
end
|
24
|
-
|
25
|
-
def accessory_text
|
26
|
-
@metadata['accessoryText']
|
27
|
-
end
|
28
|
-
|
29
|
-
def accessory_text=(val)
|
30
|
-
@metadata['accessoryText'] = val
|
31
|
-
end
|
32
|
-
|
33
|
-
def links
|
34
|
-
@metadata['links']
|
35
|
-
end
|
36
|
-
|
37
|
-
def links=(val)
|
38
|
-
@metadata['links'] = val
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
module AppleNews
|
2
|
-
class Document
|
3
|
-
module Persistence
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
def save!
|
8
|
-
request = AppleNews::Request::Post.new(endpoint_url)
|
9
|
-
request.fields = {
|
10
|
-
'metadata' => metadata_field,
|
11
|
-
'article.json' => article_json
|
12
|
-
}.merge(@files)
|
13
|
-
|
14
|
-
resp = request.call
|
15
|
-
article.update_with_data(resp['data'].delete('document'))
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def endpoint_url
|
21
|
-
if article.persisted?
|
22
|
-
"/articles/#{id}"
|
23
|
-
else
|
24
|
-
"/channels/#{AppleNews.config.channel_id}/articles"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def metadata_field
|
29
|
-
JSON.dump({ data: @metadata })
|
30
|
-
end
|
31
|
-
|
32
|
-
def article_json
|
33
|
-
UploadIO.new(
|
34
|
-
StringIO.new(JSON.dump(article.as_json)),
|
35
|
-
"application/json",
|
36
|
-
"article.json"
|
37
|
-
)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|