buttercms-ruby-zwg 2.4.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 54ecb3cd54e93defe79a22aca4f2e3a82c4f507cb6e3c1c57382f7690f0c3837
4
+ data.tar.gz: 9cd1b5498b7752d50cd560463fe99ed1866d9c9864bb85cce0dad8d50d1d64aa
5
+ SHA512:
6
+ metadata.gz: 1416c28751442d8e03235efef34aa742f0cec6eeed5d93b14fff5d519283e700c9d790e7e4e7e1c58b0ab6217cd40274a54bb944cb46c3a8a6c480ae51b6a7f8
7
+ data.tar.gz: 219c0bc189f17ecc58ac4cc7d33cde89c516d394f087af6365cb215d2787df63221bd4a281680d94d46fb65cfd6ecf660e4a1364b41aac364cf61d1421dc8ea6
@@ -0,0 +1,25 @@
1
+ # This workflow will publish a gem to rubygems.org when a release is created
2
+ # For more information see: # https://github.com/discourse/publish-rubygems-action
3
+
4
+ name: Publish Gem
5
+
6
+ on:
7
+ push:
8
+ branches:
9
+ - master
10
+
11
+ jobs:
12
+ publish:
13
+ if: github.ref == 'refs/heads/master' && github.event_name == 'push' && contains(github.event.head_commit.message, 'chore(release)')
14
+ runs-on: ubuntu-latest
15
+
16
+ steps:
17
+ - uses: actions/checkout@v3
18
+
19
+ - name: Release Gem
20
+ uses: discourse/publish-rubygems-action@v2
21
+ env:
22
+ RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
23
+ RELEASE_COMMAND: rake release
24
+ GIT_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
25
+ GIT_NAME: github-actions[bot]
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .DS_Store
19
+ .ruby-version
20
+ .rvmrc
21
+ *.rdb
22
+ *.store
23
+ test.rb
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --format documentation --color
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rake'
6
+
7
+ group :development, :test do
8
+ gem 'rspec-rails'
9
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Butter
4
+ https://buttercms.com/
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,148 @@
1
+ # ButterCMS API Ruby Client
2
+
3
+ ## Documentation
4
+
5
+ For a comprehensive list of examples, check out the [API documentation](https://buttercms.com/docs/api/).
6
+
7
+ ## Setup
8
+
9
+ To setup your project, follow these steps:
10
+
11
+ 1. Install using `gem install buttercms-ruby` or by adding to your `Gemfile`:
12
+
13
+ ```ruby
14
+ gem 'buttercms-ruby'
15
+ ```
16
+
17
+ 2. Set your API token.
18
+
19
+ ```ruby
20
+ require 'buttercms-ruby'
21
+
22
+ ButterCMS::api_token = "YourToken"
23
+
24
+ # Fetch content from test mode (eg. for your staging website)
25
+ # ButterCMS::test_mode = true
26
+
27
+ # Set read timeout (Default is 5.0)
28
+ # ButterCMS::read_timeout = 5.0
29
+
30
+ # Set open timeout (Default is 2.0)
31
+ # ButterCMS::open_timeout = 2.0
32
+ ```
33
+
34
+ ## Pages
35
+
36
+ https://buttercms.com/docs/api/?ruby#pages
37
+
38
+
39
+ ```ruby
40
+ params = {page: 1, page_size: 10, locale: 'en', preview: 1, 'fields.headline': 'foo bar', levels: 2} # optional
41
+ pages = ButterCMS::Page.list('news', params)
42
+
43
+ page = ButterCMS::Page.get('news', 'hello-world', params)
44
+
45
+ pages = ButterCMS::Page.search('query', params)
46
+ ```
47
+
48
+ ## Collections
49
+
50
+ https://buttercms.com/docs/api/?ruby#retrieve-a-collection
51
+
52
+ ```ruby
53
+ # list each instance of a given collection with meta data for fetching the next page.
54
+ params = { page: 1, page_size: 10, locale: 'en', preview: 1, 'fields.headline': 'foo bar', levels: 2 } # optional
55
+ ButterCMS::Content.list('collection1', params)
56
+
57
+ # list instances for multiple collections, this will not return meta data for pagination control.
58
+ ButterCMS::Content.fetch(['collection1', 'collection2'], params)
59
+
60
+ # Test mode can be used to setup a staging website for previewing Collections or for testing content during local development. To fetch content from test mode add the following configuration:
61
+ ButterCMS::test_mode = true
62
+ ```
63
+
64
+ ## Blog Engine
65
+
66
+ https://buttercms.com/docs/api/?ruby#blog-engine
67
+
68
+ ```ruby
69
+ posts = ButterCMS::Post.all({:page => 1, :page_size => 10})
70
+ puts posts.first.title
71
+ puts posts.meta.next_page
72
+
73
+ posts = ButterCMS::Post.search("my favorite post", {page: 1, page_size: 10})
74
+ puts posts.first.title
75
+
76
+ post = ButterCMS::Post.find("post-slug")
77
+ puts post.title
78
+
79
+ # Create a Post.
80
+ ButterCMS::write_api_token = "YourWriteToken"
81
+ ButterCMS::Post.create({
82
+ slug: 'blog-slug',
83
+ title: 'blog-title'
84
+ })
85
+
86
+ # Update a Post
87
+ ButterCMS::Post.update('blog-slug', {
88
+ title: 'blog-title-v2'
89
+ })
90
+
91
+ # Create a page
92
+ ButterCMS::Page.create({
93
+ slug: 'page-slug',
94
+ title: 'page-title',
95
+ status: 'published',
96
+ "page-type": 'page_type',
97
+ fields: {
98
+ meta_title: 'test meta title'
99
+ }
100
+ })
101
+
102
+ # update a Page
103
+ ButterCMS::Page.update('page-slug-2', {
104
+ status: 'published',
105
+ fields: {
106
+ meta_title: 'test meta title'
107
+ }
108
+ })
109
+
110
+
111
+
112
+ author = ButterCMS::Author.find("author-slug")
113
+ puts author.first_name
114
+
115
+ category = ButterCMS::Category.find("category-slug")
116
+ puts category.name
117
+
118
+ tags = ButterCMS::Tag.all
119
+ p tags
120
+
121
+ rss_feed = ButterCMS::Feed.find(:rss)
122
+ puts rss_feed.data
123
+ ```
124
+
125
+
126
+ ## Fallback Data Store
127
+
128
+ This client supports automatic fallback to a data store when API requests fail. When a data store is set, on every successful API request the response is written to the data store. When a subsequent API request fails, the client attempts to fallback to the value in the data store. Currently, Redis and YAML Store are supported.
129
+
130
+ ```ruby
131
+ # Use YAMLstore
132
+ ButterCMS::data_store = :yaml, "/File/Path/For/buttercms.store"
133
+
134
+ # Use Redis
135
+ ButterCMS::data_store = :redis, ENV['REDIS_URL']
136
+
137
+ # Use Redis over ssl store
138
+ ButterCMS.data_store = :redis_ssl, ENV["REDIS_URL"], { ca_file: "/path/to/ca.crt" }
139
+
140
+ # Set logger (optional)
141
+ ButterCMS::logger = MyLogger.new
142
+ ```
143
+
144
+ ### Other
145
+
146
+ View Ruby [Blog engine](https://buttercms.com/ruby-blog-engine/) and [Full CMS](https://buttercms.com/ruby-cms/) for other examples of using ButterCMS with Ruby.
147
+
148
+ ### Development
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ # Gem Tasks is required to run the `rake release` command
4
+ require "bundler/gem_tasks"
5
+
6
+ RSpec::Core::RakeTask.new('spec')
7
+
8
+ task :default => :spec
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
3
+
4
+ require 'buttercms/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "buttercms-ruby-zwg"
8
+ s.version = ButterCMS::VERSION
9
+ s.require_paths = ["lib"]
10
+ s.summary = 'Ruby API client for ButterCMS'
11
+ s.description = 'Butter is the #1 developer rated headless CMS. See https://buttercms.com for details.'
12
+ s.authors = ["ButterCMS"]
13
+ s.email= ["support@buttercms.com"]
14
+ s.homepage = "https://buttercms.com/docs"
15
+ s.license = 'MIT'
16
+
17
+ s.add_development_dependency 'rspec'
18
+ s.add_development_dependency 'webmock'
19
+ s.required_ruby_version = '>= 1.9.3'
20
+
21
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
+ s.files = `git ls-files`.split("\n")
23
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ end
@@ -0,0 +1,7 @@
1
+ module ButterCMS
2
+ class Author < ButterResource
3
+ def self.resource_path
4
+ "/authors/"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,22 @@
1
+ module ButterCMS
2
+ class ButterCollection
3
+ include Enumerable
4
+
5
+ attr_reader :items
6
+ attr_reader :meta
7
+
8
+ def initialize(klass, json)
9
+ data = json["data"]
10
+ meta = json["meta"]
11
+
12
+ @meta = HashToObject.convert(meta) if meta
13
+ @items = data.map {|o| klass.new("data" => o) }
14
+ end
15
+
16
+ def each(&block)
17
+ @items.each do |member|
18
+ block.call(member)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,96 @@
1
+ module ButterCMS
2
+ class ButterResource
3
+ attr_reader :meta, :data
4
+
5
+ def initialize(json)
6
+ @json = json
7
+ @data = HashToObject.convert(json["data"])
8
+ @meta = HashToObject.convert(json["meta"]) if json["meta"]
9
+
10
+ define_attribute_methods(@data)
11
+ end
12
+
13
+ def marshal_dump
14
+ { json: @json, data: @data, meta: @meta }
15
+ end
16
+
17
+ def marshal_load(dump)
18
+ @json = dump[:json]
19
+ @data = dump[:data]
20
+ @meta = dump[:meta]
21
+
22
+ define_attribute_methods(@data)
23
+ end
24
+
25
+ def inspect
26
+ id_string = (self.respond_to?(:id) && !self.id.nil?) ? " id=#{self.id}" : ""
27
+ "#<#{self.class}:0x#{self.object_id.to_s(16)}#{id_string}> JSON: " + JSON.pretty_generate(@json)
28
+ end
29
+
30
+ def self.endpoint(id = nil)
31
+ # Append trailing slash when id is added to path because
32
+ # API expects all endpoints to include trailing slashes
33
+ resource_path + (id ? "#{id}/" : '')
34
+ end
35
+
36
+ def self.patch_endpoint(id)
37
+ # Append trailing slash when id is added to path because
38
+ # API expects all endpoints to include trailing slashes
39
+ resource_path + "*/#{id}/"
40
+ end
41
+
42
+ def self.resource_path
43
+ raise "resource_path must be set"
44
+ end
45
+
46
+ def self.all(options = {})
47
+ response = ButterCMS.request(self.endpoint, options)
48
+
49
+ self.create_collection(response)
50
+ end
51
+
52
+ def self.find(id, options = {})
53
+ response = ButterCMS.request(self.endpoint(id), options)
54
+
55
+ self.create_object(response)
56
+ end
57
+
58
+ def self.create(options = {})
59
+ options[:method] = 'Post'
60
+ response = ButterCMS.write_request(self.endpoint, options)
61
+
62
+ self.create_object(response)
63
+ end
64
+
65
+ def self.update(id, options = {})
66
+ options[:method] = 'Patch'
67
+ _endpoint = if resource_path.include?("/pages/")
68
+ self.patch_endpoint(id)
69
+ else
70
+ self.endpoint(id)
71
+ end
72
+ response = ButterCMS.write_request(_endpoint, options)
73
+
74
+ self.create_object(response)
75
+ end
76
+
77
+ private
78
+
79
+ def self.create_collection(response)
80
+ ButterCollection.new(self, response)
81
+ end
82
+
83
+ def self.create_object(response)
84
+ self.new(response)
85
+ end
86
+
87
+ def define_attribute_methods(methods)
88
+ return unless methods.respond_to?(:each_pair)
89
+
90
+ methods.each_pair do |key, value|
91
+ instance_variable_set("@#{key}", value)
92
+ self.class.send(:attr_reader, key)
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,7 @@
1
+ module ButterCMS
2
+ class Category < ButterResource
3
+ def self.resource_path
4
+ "/categories/"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,20 @@
1
+ module ButterCMS
2
+ class Content < ButterResource
3
+ def self.resource_path
4
+ "/content/"
5
+ end
6
+
7
+ def self.list(collection_slug, options = {})
8
+ response = ButterCMS.request(self.endpoint(collection_slug), options)
9
+
10
+ self.create_collection(response)
11
+ end
12
+
13
+ def self.fetch(collection_slugs, options = {})
14
+ params = { keys: collection_slugs.join(',') }.merge(options)
15
+ response = ButterCMS.request(self.resource_path, params)
16
+
17
+ self.new(response)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ begin
2
+ require 'redis'
3
+ rescue LoadError
4
+ puts "WARNING: redis >= 3.0.0 is required to use the redis data store."
5
+ raise
6
+ end
7
+
8
+ module ButterCMS
9
+ module DataStoreAdapters
10
+ class Redis
11
+ def initialize(options)
12
+ redis_url = options.first
13
+
14
+ @redis = ::Redis.new(url: redis_url)
15
+ end
16
+
17
+ def set(key, value)
18
+ @redis.set(key, value)
19
+ end
20
+
21
+ def get(key)
22
+ @redis.get(key)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,27 @@
1
+ begin
2
+ require 'redis'
3
+ rescue LoadError
4
+ puts "WARNING: redis >= 3.0.0 is required to use the redis data store."
5
+ raise
6
+ end
7
+
8
+ module ButterCMS
9
+ module DataStoreAdapters
10
+ class RedisSSL
11
+ def initialize(options)
12
+ redis_url = options.first
13
+ ssl_params = options.second && Hash[options.second]
14
+
15
+ @redis = ::Redis.new(url: redis_url, ssl_params:)
16
+ end
17
+
18
+ def set(key, value)
19
+ @redis.set(key, value)
20
+ end
21
+
22
+ def get(key)
23
+ @redis.get(key)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,25 @@
1
+ require 'yaml/store'
2
+
3
+ module ButterCMS
4
+ module DataStoreAdapters
5
+ class Yaml
6
+ def initialize(options)
7
+ file_path = options.first
8
+
9
+ @store = YAML::Store.new file_path
10
+ end
11
+
12
+ def set(key, value)
13
+ @store.transaction do
14
+ @store[key] = value
15
+ end
16
+ end
17
+
18
+ def get(key)
19
+ @store.transaction do
20
+ @store[key]
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ module ButterCMS
2
+ # Error is the top level error raised by ButterCMS
3
+ class Error < StandardError
4
+ end
5
+
6
+ # NotFound is raised when a resource cannot be found
7
+ class NotFound < Error
8
+ end
9
+
10
+ class Unauthorized < Error
11
+ end
12
+
13
+ class BadRequest < Error
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module ButterCMS
2
+ class Feed < ButterResource
3
+ def self.resource_path
4
+ "/feeds/"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module ButterCMS
2
+ class HashToObject
3
+ def self.convert(hash)
4
+ JSON.parse(hash.to_json, object_class: OpenStruct, quirks_mode: true)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,25 @@
1
+ module ButterCMS
2
+ class Page < ButterResource
3
+ def self.resource_path
4
+ "/pages/"
5
+ end
6
+
7
+ def self.list(page_type, options = {})
8
+ response = ButterCMS.request(self.endpoint(page_type), options)
9
+
10
+ self.create_collection(response)
11
+ end
12
+
13
+ def self.get(page_type, slug, options = {})
14
+ response = ButterCMS.request(self.endpoint("#{page_type}/#{slug}"), options)
15
+
16
+ self.create_object(response)
17
+ end
18
+
19
+ def self.search(query = '', options = {})
20
+ response = ButterCMS.request('/pages/search/', {query: query}.merge(options))
21
+
22
+ self.create_collection(response)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ module ButterCMS
2
+ class Post < ButterResource
3
+ def self.resource_path
4
+ "/posts/"
5
+ end
6
+
7
+ def self.search(query = '', options = {})
8
+ response = ButterCMS.request('/search/', {query: query}.merge(options))
9
+
10
+ self.create_collection(response)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ module ButterCMS
2
+ class Tag < ButterResource
3
+ def self.resource_path
4
+ "/tags/"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module ButterCMS
2
+ VERSION = '2.4.1'
3
+ end
@@ -0,0 +1,194 @@
1
+ require 'json'
2
+ require 'ostruct'
3
+ require 'logger'
4
+ require 'uri'
5
+ require 'net/http'
6
+ require 'pathname'
7
+
8
+ require "buttercms/errors"
9
+ require 'buttercms/version'
10
+ require 'buttercms/hash_to_object'
11
+ require 'buttercms/butter_collection'
12
+ require 'buttercms/butter_resource'
13
+ require 'buttercms/author'
14
+ require 'buttercms/category'
15
+ require 'buttercms/tag'
16
+ require 'buttercms/post'
17
+ require 'buttercms/feed'
18
+ require 'buttercms/content'
19
+ require 'buttercms/page'
20
+
21
+ # See https://github.com/jruby/jruby/issues/3113
22
+ if RUBY_VERSION < '2.0.0'
23
+ require_relative 'core_ext/ostruct'
24
+ end
25
+
26
+ module ButterCMS
27
+ @api_url = URI.parse('https://api.buttercms.com/v2')
28
+
29
+ class << self
30
+ attr_accessor :api_token
31
+ attr_accessor :write_api_token
32
+ attr_accessor :test_mode
33
+ attr_accessor :read_timeout
34
+ attr_accessor :open_timeout
35
+ attr_reader :data_store
36
+ attr_writer :logger
37
+ end
38
+
39
+ def self.logger
40
+ @logger ||= Logger.new($stdout).tap do |log|
41
+ log.progname = "ButterCMS"
42
+ end
43
+ end
44
+
45
+ def self.data_store=(*args)
46
+ args.flatten!
47
+
48
+ if args.count < 2
49
+ raise ArgumentError.new "Wrong number of arguments"
50
+ end
51
+
52
+ strategy = args.first
53
+ options = args.drop(1)
54
+
55
+ case strategy
56
+ when :yaml
57
+ require_relative 'buttercms/data_store_adapters/yaml'
58
+ @data_store = ButterCMS::DataStoreAdapters::Yaml.new(options)
59
+ when :redis
60
+ require_relative 'buttercms/data_store_adapters/redis'
61
+ @data_store = ButterCMS::DataStoreAdapters::Redis.new(options)
62
+ when :redis_ssl
63
+ require_relative 'buttercms/data_store_adapters/redis_ssl'
64
+ @data_store = ButterCMS::DataStoreAdapters::RedisSSL.new(options)
65
+ else
66
+ raise ArgumentError.new "Invalid ButterCMS data store #{strategy}"
67
+ end
68
+ end
69
+
70
+ def self.api_request(path, options = {})
71
+ query = options.dup
72
+ query[:auth_token] ||= api_token
73
+
74
+ if test_mode
75
+ query[:test] = 1
76
+ end
77
+
78
+ # If the user has passed in a "/" leading path, don't interpret that
79
+ # as wanting to get rid of the API prefix
80
+ if path.start_with?("/")
81
+ path = path[1..-1]
82
+ end
83
+
84
+ path = Pathname.new(@api_url.path).join(path).to_s + "?#{URI.encode_www_form(query)}"
85
+
86
+ response =
87
+ Net::HTTP.start(@api_url.host, @api_url.port, http_options) do |http|
88
+ request = Net::HTTP::Get.new(path)
89
+ request["User-Agent"] = "ButterCMS/Ruby #{ButterCMS::VERSION}"
90
+ request["Accept"] = "application/json"
91
+
92
+ http.request(request)
93
+ end
94
+
95
+ case response
96
+ when Net::HTTPNotFound
97
+ raise ::ButterCMS::NotFound, JSON.parse(response.body)["detail"]
98
+ when Net::HTTPUnauthorized
99
+ raise ::ButterCMS::Unauthorized, JSON.parse(response.body)['detail']
100
+ end
101
+
102
+ response.body
103
+ end
104
+
105
+ def self.request(path, options = {})
106
+ raise ArgumentError.new "Please set your API token" unless api_token
107
+
108
+ key = "buttercms:#{path}:#{options}"
109
+
110
+ begin
111
+ result = api_request(path, options)
112
+
113
+ if data_store
114
+ data_store.set(key, result)
115
+ logger.info "Set key #{key}"
116
+ end
117
+
118
+ # TODO - more selective exception handling (SocketError)
119
+ rescue Exception => e
120
+
121
+ if data_store
122
+ if result = data_store.get(key)
123
+ logger.info "Fetched key #{key}"
124
+
125
+ # Log request error
126
+ logger.error e
127
+ else
128
+ logger.info "No data for key #{key}"
129
+ end
130
+ end
131
+
132
+ # Raise request exception if there's no data store or value returned
133
+ raise e unless data_store && result
134
+ end
135
+
136
+ return JSON.parse(result)
137
+ end
138
+
139
+ def self.write_request(path, options = {})
140
+ raise ArgumentError.new "Please set your write API token" unless write_api_token
141
+ result = write_api_request(path, options)
142
+
143
+ return JSON.parse(result)
144
+ end
145
+
146
+ def self.write_api_request(path, options = {})
147
+ query = options.dup
148
+ token_for_request = query.delete(:auth_token) || write_api_token
149
+
150
+ path = "#{@api_url.path}#{URI.encode(path)}"
151
+
152
+ response =
153
+ Net::HTTP.start(@api_url.host, @api_url.port, http_options) do |http|
154
+ write_type = query.delete(:method) || "Post"
155
+ request_type = "Net::HTTP::#{write_type}".constantize
156
+ request = request_type.new(path)
157
+ request["User-Agent"] = "ButterCMS/Ruby #{ButterCMS::VERSION}"
158
+ request["Accept"] = "application/json"
159
+ request["Content-Type"] = "application/json"
160
+ request["Authorization"] = "Token #{token_for_request}"
161
+ request.body = query.except(:auth_token).to_json
162
+
163
+ http.request(request)
164
+ end
165
+
166
+ case response
167
+ when Net::HTTPNotFound
168
+ raise ::ButterCMS::NotFound, JSON.parse(response.body)["detail"]
169
+ when Net::HTTPBadRequest
170
+ parsed_body = JSON.parse(response.body)
171
+ errors = if parsed_body.is_a?(Array)
172
+ parsed_body.join(' ')
173
+ else
174
+ parsed_body.map do |k, v|
175
+ "#{k}: #{v}"
176
+ end.join(" ")
177
+ end
178
+ raise ::ButterCMS::BadRequest, errors
179
+ end
180
+
181
+ response.body
182
+ end
183
+
184
+ private
185
+
186
+ def self.http_options
187
+ {
188
+ open_timeout: open_timeout || 2.0,
189
+ read_timeout: read_timeout || 5.0,
190
+ ssl_timeout: 2.0,
191
+ use_ssl: @api_url.scheme == "https",
192
+ }
193
+ end
194
+ end
data/lib/console.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/inline'
2
+
3
+ gemfile do
4
+ source 'https://rubygems.org'
5
+ gem 'buttercms-ruby', :path => '../buttercms-ruby'
6
+ end
7
+
8
+ # start a REPL session
9
+ ButterCMS::api_token = "" # add your dev token here
10
+ binding.irb
@@ -0,0 +1,9 @@
1
+ class OpenStruct
2
+ def [] key
3
+ send key
4
+ end unless respond_to? :[]
5
+
6
+ def []= key, val
7
+ send %(#{key}=), val
8
+ end unless respond_to? :[]=
9
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe ButterCMS do
4
+ describe '.request' do
5
+ context 'with an api token' do
6
+ before do
7
+ allow(ButterCMS).to receive(:api_token).and_return('test123')
8
+ end
9
+
10
+ it 'should make an api request' do
11
+ request = stub_request(:get, "https://api.buttercms.com/v2?auth_token=test123")
12
+ .to_return(body: JSON.generate({data: {test: 'test'}}))
13
+
14
+ ButterCMS.request('')
15
+ expect(request).to have_been_made
16
+ end
17
+
18
+ it "should properly escape paths" do
19
+ request = stub_request(
20
+ :get,
21
+ "https://api.buttercms.com/v2/pages/*/homepage%20en?auth_token=test123"
22
+ ).to_return(body: JSON.generate({data: {test: 'test'}}))
23
+
24
+ # support leading slashes
25
+ ButterCMS.request('/pages/*/homepage en')
26
+
27
+ # and no leading slashes
28
+ ButterCMS.request('pages/*/homepage en')
29
+
30
+
31
+ expect(request).to have_been_made.twice
32
+ end
33
+ end
34
+
35
+ context 'without an api token' do
36
+ it 'should throw an argument error' do
37
+ expect{ ButterCMS.request() }.to raise_error(ArgumentError)
38
+ end
39
+ end
40
+
41
+ it "raises NotFound on 404" do
42
+ allow(ButterCMS).to receive(:api_token).and_return("test123")
43
+
44
+ request = stub_request(:get, %r{/posts/slug/})
45
+ .with(query: { auth_token: "test123" })
46
+ .to_return(status: 404, body: '{"detail":"Not found."}')
47
+
48
+ expect { ButterCMS.request("/posts/slug/") }
49
+ .to raise_error(ButterCMS::NotFound)
50
+
51
+ expect(request).to have_been_made
52
+ end
53
+
54
+ it "raises Unauthorized on 401" do
55
+ allow(ButterCMS).to receive(:api_token).and_return("test")
56
+
57
+ request = stub_request(:get, %r{/posts/slug/})
58
+ .with(query: { auth_token: "test" })
59
+ .to_return(status: 401, body: '{"detail":"Invalid token."}')
60
+
61
+ expect { ButterCMS.request("/posts/slug/") }
62
+ .to raise_error(ButterCMS::Unauthorized)
63
+
64
+ expect(request).to have_been_made
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe ButterCMS::ButterCollection do
4
+ let(:json) { {"data" => ["foo"], "meta" => {}} }
5
+ let(:klass) { double('klass', :new => 'bar') }
6
+
7
+ it 'implements #items' do
8
+ collection = ButterCMS::ButterCollection.new(klass, json)
9
+
10
+ expect(collection.items).to match_array(["bar"])
11
+ end
12
+
13
+ it 'implements #meta' do
14
+ collection = ButterCMS::ButterCollection.new(klass, json)
15
+
16
+ expect(collection.meta).to be_a(OpenStruct)
17
+ end
18
+
19
+ it 'implements #count' do
20
+ collection = ButterCMS::ButterCollection.new(klass, json)
21
+
22
+ expect(collection.count).to eq 1
23
+ end
24
+
25
+ # Marshal.load (used by Rails for caching) was not restoring the ButterResource's dynamic methods
26
+ # See https://github.com/ButterCMS/buttercms-ruby/issues/13
27
+ describe 'marshal load' do
28
+ subject { described_class.new(ButterCMS::ButterResource, 'data' => [{ 'name' => 'Test Name', 'description' => 'Test Description' }]) }
29
+
30
+ it 'restores the ButterResource dynamic methods' do
31
+ collection = Marshal.load(Marshal.dump(subject))
32
+ resource = collection.first
33
+
34
+ aggregate_failures do
35
+ expect(resource.name).to eq('Test Name')
36
+ expect(resource.description).to eq('Test Description')
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe ButterCMS::ButterResource do
4
+ before do
5
+ allow(ButterCMS).to receive(:token).and_return('test123')
6
+ allow(ButterCMS).to receive(:request).and_return({"data" => [{"attribute" => 'test'}]})
7
+
8
+ allow(ButterCMS::ButterResource).to receive(:resource_path).and_return('')
9
+ end
10
+
11
+ describe 'auto-generated methods' do
12
+ let(:resource) { described_class.new('data' => { 'name' => 'Test Name', 'description' => 'Test Description' }) }
13
+
14
+ it 'creates attribute reader methods for data pairs' do
15
+ aggregate_failures do
16
+ expect(resource.name).to eq('Test Name')
17
+ expect(resource.description).to eq('Test Description')
18
+ end
19
+ end
20
+ end
21
+
22
+ describe '.all' do
23
+
24
+ it 'should make a request with the correct endpoint' do
25
+ expect(ButterCMS).to receive(:request).with('', {})
26
+ ButterCMS::ButterResource.all()
27
+ end
28
+
29
+ it 'should return a collection' do
30
+ objects = ButterCMS::ButterResource.all
31
+ expect(objects).to be_a(ButterCMS::ButterCollection)
32
+ expect(objects.first).to be_a(ButterCMS::ButterResource)
33
+ end
34
+ end
35
+
36
+ describe '.find' do
37
+ it 'should make a request with the correct endpoint' do
38
+ expect(ButterCMS).to receive(:request).with('1/', {})
39
+ ButterCMS::ButterResource.find(1)
40
+ end
41
+
42
+ it 'should return one object' do
43
+ expect(ButterCMS::ButterResource.find(1)).to be_a(ButterCMS::ButterResource)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe ButterCMS::Content do
4
+ before do
5
+ allow(ButterCMS).to receive(:token).and_return('test123')
6
+ allow(ButterCMS).to receive(:request).and_return({
7
+ "meta"=>{
8
+ "next_page"=>2,
9
+ "previous_page"=>nil,
10
+ "count"=>2
11
+ },
12
+ "data"=>{
13
+ "author"=>[
14
+ { "name"=>"Charles Dickens"},
15
+ { "name"=>"J.K. Rowling"}
16
+ ]
17
+ }
18
+ })
19
+
20
+ @response = ButterCMS::Content.list('slug', {
21
+ page: 1,
22
+ page_size: 2
23
+ })
24
+ end
25
+
26
+ it "has meta and collection info" do
27
+ expect(@response.meta.next_page).to eq(2)
28
+ expect(@response.to_a.first.data.first).to eq('author')
29
+ expect(@response.to_a.first.data.last.first).to have_attributes(
30
+ name: "Charles Dickens"
31
+ )
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe ButterCMS::HashToObject do
4
+ describe '.convert' do
5
+ it 'converts hash to object' do
6
+ hash = {
7
+ "key1" => "value",
8
+ "key2" => {
9
+ "nested_key" => "nested value"
10
+ }
11
+ }
12
+
13
+ obj = ButterCMS::HashToObject.convert(hash)
14
+
15
+ expect(obj.key1).to eq 'value'
16
+ expect(obj.key2.nested_key).to eq "nested value"
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,8 @@
1
+ $:.unshift File.expand_path('..', __FILE__)
2
+ $:.unshift File.expand_path('../../lib', __FILE__)
3
+
4
+ require 'rubygems'
5
+ require 'bundler/setup'
6
+ require 'rspec'
7
+ require 'webmock/rspec'
8
+ require 'buttercms-ruby'
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: buttercms-ruby-zwg
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.4.1
5
+ platform: ruby
6
+ authors:
7
+ - ButterCMS
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-06-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: webmock
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: 'Butter is the #1 developer rated headless CMS. See https://buttercms.com
42
+ for details.'
43
+ email:
44
+ - support@buttercms.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".github/workflows/rubygems-publish.yml"
50
+ - ".gitignore"
51
+ - ".rspec"
52
+ - Gemfile
53
+ - LICENSE
54
+ - README.md
55
+ - Rakefile
56
+ - buttercms-ruby.gemspec
57
+ - lib/buttercms-ruby.rb
58
+ - lib/buttercms/author.rb
59
+ - lib/buttercms/butter_collection.rb
60
+ - lib/buttercms/butter_resource.rb
61
+ - lib/buttercms/category.rb
62
+ - lib/buttercms/content.rb
63
+ - lib/buttercms/data_store_adapters/redis.rb
64
+ - lib/buttercms/data_store_adapters/redis_ssl.rb
65
+ - lib/buttercms/data_store_adapters/yaml.rb
66
+ - lib/buttercms/errors.rb
67
+ - lib/buttercms/feed.rb
68
+ - lib/buttercms/hash_to_object.rb
69
+ - lib/buttercms/page.rb
70
+ - lib/buttercms/post.rb
71
+ - lib/buttercms/tag.rb
72
+ - lib/buttercms/version.rb
73
+ - lib/console.rb
74
+ - lib/core_ext/ostruct.rb
75
+ - spec/lib/butter-ruby_spec.rb
76
+ - spec/lib/buttercms/butter_collection_spec.rb
77
+ - spec/lib/buttercms/butter_resource_spec.rb
78
+ - spec/lib/buttercms/content_spec.rb
79
+ - spec/lib/buttercms/hash_to_object_spec.rb
80
+ - spec/spec_helper.rb
81
+ homepage: https://buttercms.com/docs
82
+ licenses:
83
+ - MIT
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: 1.9.3
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubygems_version: 3.1.6
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: Ruby API client for ButterCMS
104
+ test_files: []