spooky 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fb5305d1096b3ab7ae0add591dad425ae012cb2105b3a7a0d64691352c28d7c5
4
+ data.tar.gz: 576d6d09c71cdc9cd6aba580d3386b80e750f314a9a2509cd49e60401dea76f3
5
+ SHA512:
6
+ metadata.gz: a8eaf6a4cabc7d44952a84eefbb7d821451d8ac9863c52240de3c10f2da1424ae3065001855b3a4df37ac110144cc71a5f468b46d1d600465c3560f8cbb89ee9
7
+ data.tar.gz: 32621bc47059575a6f909b2b3ac6e2be2332aa7218a234243db9a615d08e0d5ea33038458234f47816a0a71bf2fe016e65d30f312138582afab157d3bcfd8603
@@ -0,0 +1,10 @@
1
+ .env
2
+ /.bundle/
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,4 @@
1
+ Style/StringLiterals:
2
+ EnforcedStyle: double_quotes
3
+ AllCops:
4
+ NewCops: enable
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.6
4
+ before_install: gem install bundler -v '~> 2.0'
5
+ script: bundle exec rspec spec
@@ -0,0 +1,3 @@
1
+ # Contributor Code of Conduct
2
+
3
+ This project adheres to this document: https://www.contributor-covenant.org/version/2/0/code_of_conduct/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in spooky.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Ritchie Blair
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
13
+ all 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
21
+ THE SOFTWARE.
@@ -0,0 +1,95 @@
1
+ # :ghost: Spooky
2
+
3
+ [![Build Status](https://travis-ci.com/togethr/spooky.svg?branch=master)](https://travis-ci.com/togethr/spooky)
4
+
5
+ A simple Ruby wrapper for the [Ghost](https://ghost.org) Content API.
6
+
7
+ The Ghost Content API documentation can be found [here](https://ghost.org/docs/api/v3/content/#endpoints).
8
+
9
+ ## Installation
10
+
11
+ Add spooky to your Gemfile:
12
+
13
+ ```ruby
14
+ gem "spooky"
15
+ ```
16
+
17
+ And then run:
18
+
19
+ $ bundle
20
+
21
+ ## Usage
22
+
23
+ To get started, a Ghost client needs to be initialized using the API URL of your Ghost installation and its content API key.
24
+
25
+ ### Initializing a client (`Spooky::Client`)
26
+
27
+ #### Initialize manually
28
+
29
+ A client can be created by running the below with your credentials:
30
+
31
+ ```ruby
32
+ client = Spooky::Client.new(api_url: "https://blog.yourdomain.com", api_key: "abc123")
33
+ ```
34
+ #### Initialize with ENV variables
35
+
36
+ Spooky also has ENV variable support out of the box. You can set your credentials by setting the below ENV variables:
37
+
38
+ Attribute | ENV variable
39
+ :------------ | :--------------------
40
+ api_url | `GHOST_API_URL`
41
+ api_key | `GHOST_CONTENT_API_KEY`
42
+
43
+ If they above are set then all you have to do to initialize a client is:
44
+
45
+ ```ruby
46
+ client = Spooky::Client.new
47
+ ```
48
+ ### Fetching Posts
49
+
50
+ Spooky operates primarily on posts.
51
+
52
+ #### Get all posts
53
+ `posts = client.posts`
54
+
55
+ Returns an array of `Spooky::Post`s.
56
+
57
+ #### Get all posts and include tags and authors
58
+ `posts = client.posts(tags: true, authors: true)`
59
+
60
+ Returns an array of `Spooky::Post`s with `Spooky::Tag`s and `Spooky::Author`s where appropriate.
61
+
62
+ #### Get a post by ID or slug
63
+
64
+ `post = client.post_by(id: 'abc123')`
65
+
66
+ `post = client.post_by(slug: 'this-is-a-slug')`
67
+
68
+ Both return a `Spooky::Post`.
69
+
70
+ #### Get posts with a filter applied
71
+
72
+ Filtering accepts simple hashes as conditions or NQL strings for more complex filters.
73
+
74
+ `featured_posts = client.posts(filter: { featured: true })`
75
+
76
+ `welcome_posts = client.posts(filter: "title:Welcome")`
77
+
78
+ ## Development
79
+
80
+ 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.
81
+
82
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
83
+
84
+ ## Contributing
85
+
86
+ Create an issue with your comments or request or open a pull request with your change and accompanying tests.
87
+ This project adheres to the included Code of Conduct, see CODE_OF_CONDUCT.
88
+
89
+ ## License
90
+
91
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
92
+
93
+ ## Credits
94
+
95
+ This gem was originally developed by [infinityrobot](https://github.com/infinityrobot).
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rubocop/rake_task"
3
+ require "rspec/core/rake_task"
4
+
5
+ RuboCop::RakeTask.new
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: %i[rubocop spec]
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "spooky"
5
+
6
+ require "irb"
7
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,7 @@
1
+ require "spooky/version"
2
+
3
+ require "spooky/is_resource"
4
+ require "spooky/client"
5
+ require "spooky/post"
6
+ require "spooky/author"
7
+ require "spooky/tag"
@@ -0,0 +1,21 @@
1
+ module Spooky
2
+ class Author
3
+ ATTRIBUTES = [
4
+ "bio",
5
+ "cover_image",
6
+ "facebook",
7
+ "id",
8
+ "location",
9
+ "meta_description",
10
+ "meta_title",
11
+ "name",
12
+ "profile_image",
13
+ "slug",
14
+ "twitter",
15
+ "url",
16
+ "website"
17
+ ].freeze
18
+
19
+ include IsResource
20
+ end
21
+ end
@@ -0,0 +1,75 @@
1
+ require "http"
2
+ require "active_support/core_ext/object/blank"
3
+ require "active_support/core_ext/string/inflections"
4
+
5
+ module Spooky
6
+ class Client
7
+ attr_accessor :api_url, :api_key, :endpoint, :error
8
+
9
+ def initialize(attrs = {})
10
+ @api_url = ENV["GHOST_API_URL"] || attrs[:api_url]
11
+ @api_key = ENV["GHOST_CONTENT_API_KEY"] || attrs[:api_key]
12
+ @endpoint = "#{@api_url}/ghost/api/v3/content"
13
+ end
14
+
15
+ def fetch_json(resource, options = {})
16
+ options.merge!(key: @api_key)
17
+ url = "#{@endpoint}/#{resource}/"
18
+ response = HTTP.get(url, params: options).parse
19
+
20
+ if response["errors"].present?
21
+ @error = response["errors"]
22
+ false
23
+ else
24
+ response[resource.split("/").first]
25
+ end
26
+ end
27
+
28
+ def fetch(resource, options = {})
29
+ resource_name = resource.split("/").first
30
+ response = fetch_json(resource, options)
31
+
32
+ resource_class = "Spooky::#{resource_name.singularize.classify}".constantize
33
+
34
+ response.present? && response.map { |attrs| resource_class.send(:new, attrs) }
35
+ end
36
+
37
+ def posts(tags: false, authors: false, filter: false)
38
+ inc = []
39
+ inc << "tags" if tags
40
+ inc << "authors" if authors
41
+
42
+ options = {}
43
+ options[:include] = inc if inc.present?
44
+
45
+ if filter.present?
46
+ if filter.is_a?(Hash)
47
+ options[:filter] = filter.map { |k, v| "#{k}:#{v}" }.join
48
+ else
49
+ options[:filter] = filter
50
+ end
51
+ end
52
+
53
+ fetch("posts", options)
54
+ end
55
+
56
+ def post_by(id: nil, slug: nil, tags: false, authors: false)
57
+ inc = []
58
+ inc << "tags" if tags
59
+ inc << "authors" if authors
60
+
61
+ options = {}
62
+ options[:include] = inc if inc.present?
63
+
64
+ if id.present?
65
+ response = fetch("posts/#{id}", options)
66
+ response.present? && response.first
67
+ elsif slug.present?
68
+ response = fetch("posts/slug/#{slug}", options)
69
+ response.present? && response.first
70
+ else
71
+ false
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,26 @@
1
+ module IsResource
2
+ def self.included(base)
3
+ base.class_eval do
4
+ attr_reader(*const_get("ATTRIBUTES"))
5
+
6
+ def initialize(attrs = {})
7
+ self.class.const_get("ATTRIBUTES").each do |attribute|
8
+ instance_variable_set("@#{attribute}", attrs[attribute])
9
+ end
10
+
11
+ parse_datetimes(attrs)
12
+ parse_attributes(attrs)
13
+ end
14
+
15
+ def parse_datetimes(attrs)
16
+ ["created_at", "updated_at", "published_at"].each do |date_attr|
17
+ instance_variable_set("@#{date_attr}", DateTime.iso8601(attrs[date_attr])) if attrs[date_attr].present?
18
+ end
19
+ end
20
+
21
+ def parse_attributes(attrs)
22
+ # Abstract method, should be overridden in child if needed.
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,58 @@
1
+ module Spooky
2
+ class Post
3
+ ATTRIBUTES = [
4
+ "authors",
5
+ "canonical_url",
6
+ "codeinjection_foot",
7
+ "codeinjection_head",
8
+ "comment_id",
9
+ "created_at",
10
+ "custom_excerpt",
11
+ "custom_template",
12
+ "email_subject",
13
+ "excerpt",
14
+ "feature_image",
15
+ "featured",
16
+ "html",
17
+ "id",
18
+ "meta_description",
19
+ "meta_title",
20
+ "og_description",
21
+ "og_image",
22
+ "og_title",
23
+ "primary_author",
24
+ "primary_tag",
25
+ "published_at",
26
+ "reading_time",
27
+ "send_email_when_published",
28
+ "slug",
29
+ "tags",
30
+ "title",
31
+ "twitter_description",
32
+ "twitter_image",
33
+ "twitter_title",
34
+ "updated_at",
35
+ "url",
36
+ "uuid",
37
+ "visibility"
38
+ ].freeze
39
+
40
+ include IsResource
41
+
42
+ def parse_attributes(attrs)
43
+ author = attrs["primary_author"]
44
+ @primary_author = author.present? && Spooky::Author.new(author)
45
+
46
+ @authors = (attrs["authors"] || []).map do |author|
47
+ Spooky::Author.new(author)
48
+ end
49
+
50
+ tag = attrs["primary_tag"]
51
+ @primary_tag = tag.present? && Spooky::Tag.new(tag)
52
+
53
+ @tags = (attrs["tags"] || []).map do |tag|
54
+ Spooky::Tag.new(tag)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,17 @@
1
+ module Spooky
2
+ class Tag
3
+ ATTRIBUTES = [
4
+ "description",
5
+ "feature_image",
6
+ "id",
7
+ "meta_description",
8
+ "meta_title",
9
+ "name",
10
+ "slug",
11
+ "url",
12
+ "visibility"
13
+ ].freeze
14
+
15
+ include IsResource
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ module Spooky
2
+ VERSION = "1.0.0".freeze
3
+ end
@@ -0,0 +1,30 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "spooky/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "spooky"
7
+ spec.version = Spooky::VERSION
8
+ spec.authors = ["Georges Gabereau"]
9
+ spec.email = ["georges@togethr.app"]
10
+
11
+ spec.summary = "A simple Ruby wrapper for the Ghost Content API."
12
+ spec.description = "Access the Ghost Content API via Ruby."
13
+ spec.homepage = "https://github.com/togethr/spooky"
14
+ spec.license = "MIT"
15
+
16
+ file_match = %r{^(test|spec|features)/}
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(file_match) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_runtime_dependency "activesupport", "~> 6.0"
23
+ spec.add_runtime_dependency "http", "~> 4.0"
24
+
25
+ spec.add_development_dependency "bundler", "~> 2.0"
26
+ spec.add_development_dependency "dotenv", "~> 2.7"
27
+ spec.add_development_dependency "rake", "~> 13.0"
28
+ spec.add_development_dependency "rspec", "~> 3.9"
29
+ spec.add_development_dependency "rubocop", "~> 0.89.0"
30
+ end
metadata ADDED
@@ -0,0 +1,160 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spooky
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Georges Gabereau
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-08-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '6.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '6.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: http
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: dotenv
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.7'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.7'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '13.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '13.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.9'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.9'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.89.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.89.0
111
+ description: Access the Ghost Content API via Ruby.
112
+ email:
113
+ - georges@togethr.app
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".rspec"
120
+ - ".rubocop.yml"
121
+ - ".travis.yml"
122
+ - CODE_OF_CONDUCT.md
123
+ - Gemfile
124
+ - LICENSE.txt
125
+ - README.md
126
+ - Rakefile
127
+ - bin/console
128
+ - bin/setup
129
+ - lib/spooky.rb
130
+ - lib/spooky/author.rb
131
+ - lib/spooky/client.rb
132
+ - lib/spooky/is_resource.rb
133
+ - lib/spooky/post.rb
134
+ - lib/spooky/tag.rb
135
+ - lib/spooky/version.rb
136
+ - spooky.gemspec
137
+ homepage: https://github.com/togethr/spooky
138
+ licenses:
139
+ - MIT
140
+ metadata: {}
141
+ post_install_message:
142
+ rdoc_options: []
143
+ require_paths:
144
+ - lib
145
+ required_ruby_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ requirements: []
156
+ rubygems_version: 3.0.3
157
+ signing_key:
158
+ specification_version: 4
159
+ summary: A simple Ruby wrapper for the Ghost Content API.
160
+ test_files: []