postwave-client 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/README.md +95 -0
- data/Rakefile +10 -0
- data/lib/postwave/blog_utilities.rb +40 -0
- data/lib/postwave/client.rb +92 -0
- data/lib/postwave/errors.rb +16 -0
- data/lib/postwave/post.rb +67 -0
- data/lib/postwave/version.rb +3 -0
- data/lib/postwave.rb +6 -0
- data/postwave-client.gemspec +24 -0
- metadata +81 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: dcf237beec10b8cff85f7ca70cb4f63a23b43555c70a0fa00d20fbbf01abc7d2
|
4
|
+
data.tar.gz: 6400cff762bb34f29084d3ca21de96c97e395239e79592bc53c476ac636b46cf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2c4611af08d26282c042f9695a7291d07ab1eb103fadf082e6a505f63297c20411848c9dba7669c9a63d7beeb15f5ef5ed0b52c83a0b6bbd72ce7a0cbd8fe5ba
|
7
|
+
data.tar.gz: 7314600e6fea02aac7cfb9359f8ac82d254efc54f5bf302a278e1dd6f5cf358d2d2a233371a455c45472501a6699a62b78ba67c66acb8d2a66884f4cc2113e0b
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.gem
|
data/README.md
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
# Postwave Ruby Client 🌊
|
2
|
+
|
3
|
+
A Ruby client for displaying [Postwave](https://github.com/dorkrawk/postwave) blogs.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
```
|
8
|
+
gem install postwave-client
|
9
|
+
```
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
### Create a Postwave Client
|
14
|
+
```ruby
|
15
|
+
postwave_client = Postwave::Client.new("path/to/config/postwave.yaml")
|
16
|
+
```
|
17
|
+
|
18
|
+
If you'd like to preload all the posts:
|
19
|
+
```ruby
|
20
|
+
postwave_client = Postwave::Client.new("path/to/config/postwave.yaml", preload: true)
|
21
|
+
```
|
22
|
+
|
23
|
+
### Get a Single Post
|
24
|
+
|
25
|
+
Pass in the stub (the filename without '.md') for the post.
|
26
|
+
```ruby
|
27
|
+
post = postwave_client.post("my-great-post")
|
28
|
+
|
29
|
+
# <Postwave::Post title="My Great Post", date=<Time ...>, tags=["tag1"], body="bla bla bla..">
|
30
|
+
|
31
|
+
puts post.title
|
32
|
+
# "My Great Post"
|
33
|
+
```
|
34
|
+
|
35
|
+
### Get a Collection of Posts
|
36
|
+
|
37
|
+
This will give you a list of posts for displaying on a page.
|
38
|
+
|
39
|
+
You can also filter by tags and specify offsets and limits (useful for pagination).
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
posts = postwave_client.posts
|
43
|
+
|
44
|
+
# [<Postwave::Post ...>, <Postwave::Post ...>, ...]
|
45
|
+
|
46
|
+
tagged_posts = postwave_client.posts(tag: "lizards")
|
47
|
+
|
48
|
+
page2_posts = postwave_client.posts(offset: 10, limit: 10)
|
49
|
+
```
|
50
|
+
Posts will be in reverse chronological order.
|
51
|
+
|
52
|
+
### Get an Index of Posts
|
53
|
+
|
54
|
+
This will give you a quick list of post summaries containing the title, date, and stub, useful for building an archive page or quick index of posts.
|
55
|
+
|
56
|
+
You can also specify offsets and limits (useful for pagination).
|
57
|
+
```ruby
|
58
|
+
index = postwave_client(index)
|
59
|
+
|
60
|
+
# [<Postwave::PostStub title="My Great Post", date=<Time ...>, stub="my-great-post">, <Postwave::PostStub ...>, ...]
|
61
|
+
|
62
|
+
puts index.first.stub
|
63
|
+
# my-great-post
|
64
|
+
|
65
|
+
page2_index = postwave_client.index(offset: 10, limit: 10)
|
66
|
+
```
|
67
|
+
Index will be in reverse chronological order.
|
68
|
+
|
69
|
+
### Get Tags Used In the Blog
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
tags = postwave_client.tags
|
73
|
+
|
74
|
+
# ["tag1", "tag2", "another-tag"]
|
75
|
+
```
|
76
|
+
|
77
|
+
### Get Details For A Tag
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
tag = postwave_clinet.tag("tag1")
|
81
|
+
|
82
|
+
# <Postwave::Tag tile="tag1", count=1, post_slugs=["my-great-post"]>
|
83
|
+
```
|
84
|
+
|
85
|
+
## Want To Know More About Postwave?
|
86
|
+
|
87
|
+
Check out the [Postwave](https://github.com/dorkrawk/postwave) repo.
|
88
|
+
|
89
|
+
## Development
|
90
|
+
|
91
|
+
### Run the Tests!
|
92
|
+
|
93
|
+
```
|
94
|
+
rake test
|
95
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Postwave
|
2
|
+
module BlogUtilities
|
3
|
+
CONFIG_FILE_NAME = "postwave.yaml"
|
4
|
+
INDEX_FILE_NAME = "index.csv"
|
5
|
+
SUMMARY_FILE_NAME = "summary.yaml"
|
6
|
+
POSTS_DIR = "_posts"
|
7
|
+
META_DIR = "meta"
|
8
|
+
TAGS_DIR = "tags"
|
9
|
+
|
10
|
+
def is_set_up?(blog_root)
|
11
|
+
missing_paths = find_missing_paths(blog_root)
|
12
|
+
missing_paths.empty?
|
13
|
+
end
|
14
|
+
|
15
|
+
def file_paths(blog_root)
|
16
|
+
[
|
17
|
+
File.join(blog_root, CONFIG_FILE_NAME),
|
18
|
+
File.join(blog_root, POSTS_DIR, META_DIR, INDEX_FILE_NAME),
|
19
|
+
File.join(blog_root, POSTS_DIR, META_DIR, SUMMARY_FILE_NAME),
|
20
|
+
]
|
21
|
+
end
|
22
|
+
|
23
|
+
def directory_paths(blog_root)
|
24
|
+
[
|
25
|
+
File.join(blog_root, POSTS_DIR),
|
26
|
+
File.join(blog_root, POSTS_DIR, META_DIR),
|
27
|
+
File.join(blog_root, POSTS_DIR, META_DIR, TAGS_DIR),
|
28
|
+
]
|
29
|
+
end
|
30
|
+
|
31
|
+
def find_missing_paths(blog_root)
|
32
|
+
paths_to_check = directory_paths(blog_root) + file_paths(blog_root)
|
33
|
+
missing_paths = []
|
34
|
+
paths_to_check.each do |path|
|
35
|
+
missing_paths << path if !FileTest.exist?(path)
|
36
|
+
end
|
37
|
+
missing_paths
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require_relative "post"
|
2
|
+
require_relative "errors"
|
3
|
+
require_relative "blog_utilities"
|
4
|
+
|
5
|
+
require "csv"
|
6
|
+
require "time"
|
7
|
+
require "yaml"
|
8
|
+
|
9
|
+
module Postwave
|
10
|
+
class Client
|
11
|
+
include BlogUtilities
|
12
|
+
|
13
|
+
def initialize(config_path, preload: false)
|
14
|
+
raise MissingConfigError unless is_valid_config?(config_path)
|
15
|
+
|
16
|
+
@blog_root = File.dirname(config_path)
|
17
|
+
raise InvalidBlogError unless is_set_up?(@blog_root)
|
18
|
+
|
19
|
+
@all_posts = get_all_posts if preload
|
20
|
+
end
|
21
|
+
|
22
|
+
# returns: an array of PostStub Structs - [<struct PostStub date=Time, title="", stub="">]
|
23
|
+
def index(offset: 0, limit: nil)
|
24
|
+
working_index = @full_index || get_full_index
|
25
|
+
count = limit || working_index.size
|
26
|
+
working_index[offset, count]
|
27
|
+
end
|
28
|
+
|
29
|
+
# returns: a post - Postwave::Post
|
30
|
+
def post(slug)
|
31
|
+
post_file_path = Dir["#{File.join(@blog_root, POSTS_DIR)}/*#{slug}.md"].first
|
32
|
+
|
33
|
+
raise PostNotFoundError unless post_file_path && File.exist?(post_file_path)
|
34
|
+
|
35
|
+
Postwave::Post.new_from_file_path(post_file_path)
|
36
|
+
end
|
37
|
+
|
38
|
+
# returns: an array of posts - [Postwave::Post]
|
39
|
+
def posts(offset: 0, limit: nil, tag: nil)
|
40
|
+
posts = @all_posts || get_all_posts
|
41
|
+
posts = posts.select { |post| post.tags.include?(tag) } if tag
|
42
|
+
count = limit || posts.size
|
43
|
+
posts[offset, count]
|
44
|
+
end
|
45
|
+
|
46
|
+
# returns: an array of tags - [String]
|
47
|
+
def tags
|
48
|
+
summary = @blog_summary || get_summary
|
49
|
+
summary[:tags]
|
50
|
+
end
|
51
|
+
|
52
|
+
# returns: a Tag Struct - <Tag tag: "", count: Integer, post_slugs: ["post-slug",..]
|
53
|
+
def tag(tag)
|
54
|
+
tag_file_path = File.join(@blog_root, POSTS_DIR, META_DIR, TAGS_DIR, "#{tag}.yaml")
|
55
|
+
raise TagNotFoundError unless File.exist?(tag_file_path)
|
56
|
+
|
57
|
+
tag_info = YAML.load_file(tag_file_path)
|
58
|
+
|
59
|
+
Postwave::Tag.new(tag, tag_info[:count], tag_info[:post_slugs])
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def is_valid_config?(config_path)
|
65
|
+
File.exist?(config_path)
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_all_posts
|
69
|
+
posts = []
|
70
|
+
Dir.glob(File.join(@blog_root, POSTS_DIR, "*.md")) do |post_file_path|
|
71
|
+
posts << Postwave::Post.new_from_file_path(post_file_path)
|
72
|
+
end
|
73
|
+
posts.reject! { |p| p.draft if p.respond_to? :draft }
|
74
|
+
posts.sort_by { |p| p.date }.reverse
|
75
|
+
end
|
76
|
+
|
77
|
+
def get_full_index
|
78
|
+
full_index = []
|
79
|
+
index_contents = CSV.read(File.join(@blog_root, POSTS_DIR, META_DIR, INDEX_FILE_NAME))
|
80
|
+
index_contents.shift # skip header
|
81
|
+
index_contents.each do |post|
|
82
|
+
full_index << Postwave::PostStub.new(Time.parse(post[1]), post[2], post[0])
|
83
|
+
end
|
84
|
+
full_index
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_summary
|
88
|
+
summary_file_path = File.join(@blog_root, POSTS_DIR, META_DIR, SUMMARY_FILE_NAME)
|
89
|
+
YAML.load_file(summary_file_path)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Postwave
|
2
|
+
class PostwaveError < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class MissingConfigError < PostwaveError
|
6
|
+
end
|
7
|
+
|
8
|
+
class InvalidBlogError < PostwaveError
|
9
|
+
end
|
10
|
+
|
11
|
+
class PostNotFoundError < PostwaveError
|
12
|
+
end
|
13
|
+
|
14
|
+
class TagNotFoundError < PostwaveError
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require_relative "blog_utilities"
|
2
|
+
|
3
|
+
module Postwave
|
4
|
+
class Post
|
5
|
+
include BlogUtilities
|
6
|
+
|
7
|
+
MEATADATA_DELIMTER = "---"
|
8
|
+
|
9
|
+
attr_reader :file_name, :slug
|
10
|
+
|
11
|
+
def self.new_from_file_path(path)
|
12
|
+
metadata_delimter_count = 0
|
13
|
+
body_buffer_count = 0
|
14
|
+
field_content = { "body" => "" }
|
15
|
+
|
16
|
+
File.readlines(path).each do |line|
|
17
|
+
clean_line = line.chomp
|
18
|
+
if clean_line == MEATADATA_DELIMTER
|
19
|
+
metadata_delimter_count += 1
|
20
|
+
next
|
21
|
+
end
|
22
|
+
|
23
|
+
if metadata_delimter_count == 0
|
24
|
+
next
|
25
|
+
elsif metadata_delimter_count == 1
|
26
|
+
field, value = clean_line.split(":", 2).map(&:strip)
|
27
|
+
field_content[field] = value
|
28
|
+
else
|
29
|
+
if body_buffer_count == 0
|
30
|
+
body_buffer_count += 1
|
31
|
+
next if clean_line.empty?
|
32
|
+
end
|
33
|
+
|
34
|
+
field_content["body"] += "#{line}\n"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# turn "date" into a Time object
|
39
|
+
field_content["date"] = Time.parse(field_content["date"])
|
40
|
+
|
41
|
+
# turn "tags" into an array
|
42
|
+
if field_content["tags"]
|
43
|
+
field_content["tags"] = field_content["tags"].split(",").map do |tag|
|
44
|
+
tag.downcase.strip.gsub(' ', '-').gsub(/[^\w-]/, '')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# turn "draft" into boolean
|
49
|
+
if field_content["draft"]
|
50
|
+
field_content["draft"] = field_content["draft"].downcase == "true"
|
51
|
+
end
|
52
|
+
|
53
|
+
self.new(path, field_content)
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize(file_name, field_content = {})
|
57
|
+
@file_name = file_name
|
58
|
+
@slug = file_name.split("/").last[...-3] # cut off ".md"
|
59
|
+
|
60
|
+
field_content.each do |field, value|
|
61
|
+
instance_variable_set("@#{field}", value) unless self.instance_variables.include?("@#{field}".to_sym)
|
62
|
+
self.class.send(:attr_reader, field) unless self.public_methods.include?(field.to_sym)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
data/lib/postwave.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'postwave/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "postwave-client"
|
8
|
+
spec.version = Postwave::VERSION
|
9
|
+
spec.authors = ["Dave Schwantes"]
|
10
|
+
spec.email = ["dave.schwantes@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = "A Ruby client for interacting with Postwave blogs."
|
13
|
+
spec.description = "Write your posts statically. Interact with them dynamically."
|
14
|
+
spec.homepage = "https://github.com/dorkrawk/postwave-client-ruby"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
# spec.add_dependency ""
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler"
|
23
|
+
spec.add_development_dependency "rake", "~> 12.3"
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: postwave-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dave Schwantes
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-09-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
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: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '12.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '12.3'
|
41
|
+
description: Write your posts statically. Interact with them dynamically.
|
42
|
+
email:
|
43
|
+
- dave.schwantes@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".gitignore"
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- lib/postwave.rb
|
52
|
+
- lib/postwave/blog_utilities.rb
|
53
|
+
- lib/postwave/client.rb
|
54
|
+
- lib/postwave/errors.rb
|
55
|
+
- lib/postwave/post.rb
|
56
|
+
- lib/postwave/version.rb
|
57
|
+
- postwave-client.gemspec
|
58
|
+
homepage: https://github.com/dorkrawk/postwave-client-ruby
|
59
|
+
licenses:
|
60
|
+
- MIT
|
61
|
+
metadata: {}
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
requirements: []
|
77
|
+
rubygems_version: 3.2.22
|
78
|
+
signing_key:
|
79
|
+
specification_version: 4
|
80
|
+
summary: A Ruby client for interacting with Postwave blogs.
|
81
|
+
test_files: []
|