postwave 0.1.2 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b4511f2e9288a14247515ff919efbcdfaf4aef9f7e6ae5d7de5c207795307d73
4
- data.tar.gz: 6997bdd3f519948e40fbf701d792bc761e0d563f23bd171b47cf35b6ba652fb8
3
+ metadata.gz: d05bcd73c7411550217ca5ecbeed284b472a25aac71493b401bac88b8c756cab
4
+ data.tar.gz: 58b7c971cc36fe07783176414d530ec96962d9b921a854d2d1580322fc9fb718
5
5
  SHA512:
6
- metadata.gz: 3248a5fdd235809dee5026f53ecf5dd637c96a3e69e6acff19d91617a6632ae61e49989a79dd16f91258b21de14d54ed748b31af5dbb2974d3e0c97d6f65accf
7
- data.tar.gz: 74bd0b0f980cb534b63c06a3374e4d1e807c68113cf18cc56f1bf6aa601adb4b4c2ae0c5bb55103ed2d2a496064b1b730435933dda937eb2aa446a92bf3279fc
6
+ metadata.gz: 9ea1bcd8a913e043d49b99a3687fd3d97c12a1dbc60d938b3f35ceb3995df7eec1b33801f2f1adcc2295ebde903d5be6d90c21655b4bc23b19f137b7195d6130
7
+ data.tar.gz: 7b52272bb286fe4ed33490e70ed541a9853e1d8191a5f5397292ecb38e45bbae4dffaa8b20a5828423f81bca88c14468a5ee16ff588833741db6d429d3d8f02d
data/README.md CHANGED
@@ -113,18 +113,20 @@ postwave_client = Postwave::Client.new("path/to/config/postwave.yaml", preload:
113
113
 
114
114
  ### Get a Single Post
115
115
 
116
- Pass in the stub (the filename without '.md') for the post.
116
+ Pass in the stub (the filename without the date and '.md') for the post.
117
117
  ```ruby
118
118
  post = postwave_client.post("my-great-post")
119
119
 
120
- # <Postwave::Post title="My Great Post", date=<Time ...>, tags=["tag1"], body="bla bla bla..">
120
+ # <Postwave::Post title="My Great Post", date=<Time ...>, tags=["tag1"], body="bla bla bla">
121
121
 
122
122
  puts post.title
123
123
  # "My Great Post"
124
124
  puts post.body
125
- # "bla bla bla..."
125
+ # "bla bla bla"
126
126
  puts post.body_html # uses Redcarpt to convert body Markdown to HTML
127
- # "<p>bla bla bla...</p>"
127
+ # "<p>bla bla bla</p>"
128
+ puts post.body_preview(8) # an HTML free preview of the post with optional `limit` and `ellipsis` params
129
+ # "bla bla..."
128
130
  ```
129
131
 
130
132
  ### Get a Collection of Posts
@@ -32,7 +32,7 @@ module Postwave
32
32
 
33
33
  def archive(by: "year")
34
34
  working_index = @full_index || get_full_index
35
- post_hash = posts.group_by { |post| post.date.year }.transform_values { |posts| posts.sort_by(&:date) }
35
+ post_hash = working_index.group_by { |post| post.date.year }.transform_values { |posts| posts.sort_by(&:date) }
36
36
  if by == "month"
37
37
  post_hash.each do |key, value|
38
38
  post_hash[key] = value.group_by { |post| post.date.month }
@@ -119,7 +119,7 @@ module Postwave
119
119
 
120
120
  def get_summary
121
121
  summary_file_path = File.join(@blog_root, POSTS_DIR, META_DIR, SUMMARY_FILE_NAME)
122
- YAML.load_file(summary_file_path)
122
+ YAML.load_file(summary_file_path, permitted_classes: [Time, Symbol])
123
123
  end
124
124
  end
125
125
  end
data/lib/postwave/post.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require_relative "blog_utilities"
2
2
  require "redcarpet"
3
+ require "cgi"
3
4
 
4
5
  module Postwave
5
6
  class Post
@@ -7,7 +8,8 @@ module Postwave
7
8
 
8
9
  KNOWN_FIELDS = %w(title date tags title_slug body draft)
9
10
  REQUIRED_FIELDS = %w(title date)
10
- MEATADATA_DELIMTER = "---"
11
+ METADATA_DELIMITER = "---"
12
+ FILE_NAME_DATE_LEN = 11 # YYYY-MM-DD-
11
13
 
12
14
  attr_accessor :file_name
13
15
 
@@ -20,7 +22,7 @@ module Postwave
20
22
 
21
23
  File.readlines(path).each do |line|
22
24
  clean_line = line.strip
23
- if clean_line == MEATADATA_DELIMTER
25
+ if clean_line == METADATA_DELIMITER
24
26
  metadata_delimter_count += 1
25
27
  next
26
28
  end
@@ -65,11 +67,18 @@ module Postwave
65
67
  instance_variable_set("@#{field}", value) unless self.instance_variables.include?("@#{field}".to_sym)
66
68
  self.class.send(:attr_reader, field) unless self.public_methods.include?(field.to_sym)
67
69
  end
70
+
71
+ @slug = file_name_slug&.empty? ? title_slug : file_name_slug
68
72
  end
69
73
 
70
74
  def title_slug
71
75
  @title_slug ||= @title.downcase.strip.gsub(' ', '-').gsub(/[^\w-]/, '')
72
76
  end
77
+
78
+ def file_name_slug
79
+ # YYYY-MM-DD-slug.md
80
+ File.basename(@file_name, ".md")[FILE_NAME_DATE_LEN..]
81
+ end
73
82
 
74
83
  def slug
75
84
  @slug ||= @title_slug
@@ -80,7 +89,34 @@ module Postwave
80
89
  end
81
90
 
82
91
  def body_html
83
- @@markdown.render(@body)
92
+ @body_html ||= @@markdown.render(@body)
93
+ end
94
+
95
+ def body_preview(limit = 100, ellipsis = "...")
96
+ text = body_html.to_s
97
+
98
+ # Turn common block boundaries into newlines first
99
+ text = text.gsub(/<(br|\/p|\/div|\/h\d|\/li)[^>]*>/i, "\n")
100
+ # Strip remaining tags
101
+ text = text.gsub(/<[^>]*>/, "")
102
+ # Decode entities
103
+ text = CGI.unescapeHTML(text)
104
+ # Collapse spaces but keep single newlines
105
+ text = text.gsub(/[ \t]+/, " ").gsub(/\n+/, "\n").strip
106
+
107
+ # Unicode-safe character counting (grapheme clusters)
108
+ graphemes = text.scan(/\X/)
109
+ return text if graphemes.length <= limit
110
+
111
+ candidate = graphemes.first(limit).join
112
+
113
+ # If we cut mid-word, trim back to the previous word boundary.
114
+ # Word characters = letters, numbers, marks, connector punctuation (e.g., underscore)
115
+ # This removes a trailing partial word if present.
116
+ cut = candidate.sub(/[\p{L}\p{N}\p{M}\p{Pc}]+\z/u, "").rstrip
117
+
118
+ # If the very first "word" exceeds the limit, we err under limit and just show an ellipsis.
119
+ cut.empty? ? ellipsis : "#{cut}#{ellipsis}"
84
120
  end
85
121
 
86
122
  def generated_file_name
@@ -1,3 +1,3 @@
1
1
  module Postwave
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
data/postwave.gemspec CHANGED
@@ -19,7 +19,12 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "redcarpet", '~> 3.6'
22
+ spec.add_dependency "csv"
23
+ spec.add_dependency "time"
24
+ spec.add_dependency "yaml"
25
+
22
26
 
23
27
  spec.add_development_dependency "bundler"
24
28
  spec.add_development_dependency "rake", "~> 12.3"
29
+ spec.add_development_dependency "rss"
25
30
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: postwave
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dave Schwantes
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-03-13 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: redcarpet
@@ -24,6 +23,48 @@ dependencies:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
25
  version: '3.6'
26
+ - !ruby/object:Gem::Dependency
27
+ name: csv
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: time
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: yaml
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
27
68
  - !ruby/object:Gem::Dependency
28
69
  name: bundler
29
70
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +93,20 @@ dependencies:
52
93
  - - "~>"
53
94
  - !ruby/object:Gem::Version
54
95
  version: '12.3'
96
+ - !ruby/object:Gem::Dependency
97
+ name: rss
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
55
110
  description: Write your posts statically. Interact with them dynamically.
56
111
  email:
57
112
  - dave.schwantes@gmail.com
@@ -83,7 +138,6 @@ homepage: https://github.com/dorkrawk/postwave
83
138
  licenses:
84
139
  - MIT
85
140
  metadata: {}
86
- post_install_message:
87
141
  rdoc_options: []
88
142
  require_paths:
89
143
  - lib
@@ -98,8 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
152
  - !ruby/object:Gem::Version
99
153
  version: '0'
100
154
  requirements: []
101
- rubygems_version: 3.2.22
102
- signing_key:
155
+ rubygems_version: 3.7.1
103
156
  specification_version: 4
104
157
  summary: An opinionated flatfile based blog engine.
105
158
  test_files: []