md_record 0.1.0
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 +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +143 -0
- data/Rakefile +11 -0
- data/lib/md_record/base.rb +90 -0
- data/lib/md_record/categorizable.rb +55 -0
- data/lib/md_record/categorized_loader.rb +28 -0
- data/lib/md_record/category.rb +17 -0
- data/lib/md_record/frontmatter_parser.rb +48 -0
- data/lib/md_record/loader.rb +19 -0
- data/lib/md_record/markdown_renderer.rb +30 -0
- data/lib/md_record/railtie.rb +9 -0
- data/lib/md_record/record_not_found.rb +25 -0
- data/lib/md_record/version.rb +5 -0
- data/lib/md_record.rb +22 -0
- data/md_record.gemspec +31 -0
- metadata +102 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 616c429f1a3a4330fce85c47841213fc47a4cfeb15efc8606af343dc9134e302
|
|
4
|
+
data.tar.gz: 8f5c9d8ad4354d5d2ddc143ba19d999e11de5a0f40706479472bb3bc3e50f134
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: e581cd2950f178ea6806092df5746d9add34d9fe2fd8494a0bd5a9c7ea71d376e71cd86f75533fb43dcf8496403e42723b96f6d9e3f687ee0e73318e72050531
|
|
7
|
+
data.tar.gz: ddd1bc077f3b20b757a9bc25e8075e88db637340f7413b4077cee31def87ab05894ee6c73342257cfa8bfcde61f3cbb4dfa32f175916c37b3ea613481ea19063
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Benito Serna
|
|
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.
|
data/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# MdRecord
|
|
2
|
+
|
|
3
|
+
File-backed models for Rails. Similar to ActiveRecord but reads from markdown files with YAML frontmatter.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem "md_record"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
And then execute:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bundle install
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Basic Model
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
class Post < MdRecord::Base
|
|
25
|
+
end
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
By default, files are loaded from `app/views/posts/` (based on model name).
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
Post.all # All posts
|
|
32
|
+
Post.published # Only published posts
|
|
33
|
+
Post.find(slug) # Find by slug or raise MdRecord::RecordNotFound
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Custom Path
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
class Article < MdRecord::Base
|
|
40
|
+
md_record_path "content/articles"
|
|
41
|
+
end
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Categorized Model
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
class Guide < MdRecord::Base
|
|
48
|
+
include MdRecord::Categorizable
|
|
49
|
+
|
|
50
|
+
md_record_categories(
|
|
51
|
+
"getting-started" => { name: "Getting Started", position: 1 },
|
|
52
|
+
"advanced" => { name: "Advanced", position: 2 }
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Files are organized in subfolders:
|
|
58
|
+
```
|
|
59
|
+
app/views/guides/
|
|
60
|
+
getting-started/
|
|
61
|
+
first-steps.md
|
|
62
|
+
advanced/
|
|
63
|
+
custom-config.md
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
Guide.categories # Returns array of MdRecord::Category objects
|
|
68
|
+
guide.category?("getting-started") # Check if guide belongs to category
|
|
69
|
+
guide.category_name # "Getting Started"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## File Format
|
|
73
|
+
|
|
74
|
+
Markdown files with YAML frontmatter:
|
|
75
|
+
|
|
76
|
+
```markdown
|
|
77
|
+
---
|
|
78
|
+
title: My Post Title
|
|
79
|
+
description: A short description
|
|
80
|
+
published: true
|
|
81
|
+
published_at: 2024-01-15
|
|
82
|
+
position: 1
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
# Content here
|
|
86
|
+
|
|
87
|
+
Your markdown content...
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Attributes
|
|
91
|
+
|
|
92
|
+
- `slug` - Filename without extension
|
|
93
|
+
- `title` - From frontmatter or titleized slug
|
|
94
|
+
- `description` - From frontmatter
|
|
95
|
+
- `content` - Markdown content
|
|
96
|
+
- `published` - Boolean
|
|
97
|
+
- `published_at` - Date/Time
|
|
98
|
+
- `position` - For ordering
|
|
99
|
+
|
|
100
|
+
## Methods
|
|
101
|
+
|
|
102
|
+
### Class Methods
|
|
103
|
+
|
|
104
|
+
- `all` - Load all records
|
|
105
|
+
- `published` - Published records sorted by `published_at` desc
|
|
106
|
+
- `find(slug)` - Find by slug, raises `RecordNotFound` if not found
|
|
107
|
+
|
|
108
|
+
### Instance Methods
|
|
109
|
+
|
|
110
|
+
- `published?` - Is this record published?
|
|
111
|
+
- `to_param` - Returns slug (for URL generation)
|
|
112
|
+
- `to_html` - Renders markdown to HTML
|
|
113
|
+
|
|
114
|
+
### Categorizable Methods
|
|
115
|
+
|
|
116
|
+
- `categories` - Array of `MdRecord::Category` objects
|
|
117
|
+
- `category?(category)` - Check if record belongs to category (accepts Category or string)
|
|
118
|
+
- `category_name` - Human-readable category name
|
|
119
|
+
|
|
120
|
+
## RecordNotFound
|
|
121
|
+
|
|
122
|
+
`MdRecord::RecordNotFound` is automatically mapped to 404 in Rails (via Railtie).
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
Post.find("non-existent") # raises MdRecord::RecordNotFound
|
|
126
|
+
# Rails returns 404
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Components
|
|
130
|
+
|
|
131
|
+
- `MdRecord::Base` - Base class for models
|
|
132
|
+
- `MdRecord::Categorizable` - Concern for categorized models
|
|
133
|
+
- `MdRecord::Category` - Value object for categories
|
|
134
|
+
- `MdRecord::Loader` - Loads files from a directory
|
|
135
|
+
- `MdRecord::CategorizedLoader` - Loads files from category subdirectories
|
|
136
|
+
- `MdRecord::FrontmatterParser` - Parses YAML frontmatter
|
|
137
|
+
- `MdRecord::MarkdownRenderer` - Custom Redcarpet renderer with asset path support
|
|
138
|
+
- `MdRecord::RecordNotFound` - Exception for missing records
|
|
139
|
+
- `MdRecord::Railtie` - Rails integration (auto-loaded)
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MdRecord
|
|
4
|
+
class Base
|
|
5
|
+
include ActiveModel::Model
|
|
6
|
+
|
|
7
|
+
attr_accessor :slug, :title, :content, :published,
|
|
8
|
+
:published_at, :description, :position
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
def md_record_path(path = nil)
|
|
12
|
+
@md_record_path = path if path
|
|
13
|
+
@md_record_path || default_path
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def loader
|
|
17
|
+
MdRecord::Loader.new(path: resolve_path(md_record_path))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def parse(file)
|
|
21
|
+
parser = MdRecord::FrontmatterParser.new(file).parse!
|
|
22
|
+
|
|
23
|
+
new(
|
|
24
|
+
slug: parser.slug,
|
|
25
|
+
title: parser.title,
|
|
26
|
+
content: parser.content,
|
|
27
|
+
published: parser.published,
|
|
28
|
+
published_at: parser.frontmatter["published_at"],
|
|
29
|
+
description: parser.frontmatter["description"],
|
|
30
|
+
position: parser.frontmatter.fetch("position", 0)
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def all
|
|
35
|
+
loader.load { |file| parse(file) }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def published
|
|
39
|
+
@published ||= all.select(&:published?).sort_by(&:published_at).reverse
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def find(slug)
|
|
43
|
+
published.find { |doc| doc.slug == slug } ||
|
|
44
|
+
raise(RecordNotFound.new(model: name, slug: slug))
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def default_path
|
|
50
|
+
"app/views/#{model_name.plural}"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def resolve_path(path)
|
|
54
|
+
if defined?(Rails.root) && Rails.root
|
|
55
|
+
Rails.root.join(path).to_s
|
|
56
|
+
else
|
|
57
|
+
path
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def published?
|
|
63
|
+
published
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def to_param
|
|
67
|
+
slug
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def to_html
|
|
71
|
+
options = {
|
|
72
|
+
autolink: true,
|
|
73
|
+
tables: true,
|
|
74
|
+
fenced_code_blocks: true,
|
|
75
|
+
strikethrough: true,
|
|
76
|
+
no_intra_emphasis: true
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
renderer = MdRecord::MarkdownRenderer.new(hard_wrap: true)
|
|
80
|
+
markdown = Redcarpet::Markdown.new(renderer, options)
|
|
81
|
+
result = markdown.render(content)
|
|
82
|
+
|
|
83
|
+
if result.respond_to?(:html_safe)
|
|
84
|
+
result.html_safe
|
|
85
|
+
else
|
|
86
|
+
result
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MdRecord
|
|
4
|
+
module Categorizable
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
included do
|
|
8
|
+
attr_accessor :category
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class_methods do
|
|
12
|
+
def md_record_categories(categories)
|
|
13
|
+
@md_record_categories = categories
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def loader
|
|
17
|
+
MdRecord::CategorizedLoader.new(
|
|
18
|
+
path: resolve_path(md_record_path),
|
|
19
|
+
categories: @md_record_categories
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def parse(file, category:)
|
|
24
|
+
super(file).tap { |doc| doc.category = category }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def all
|
|
28
|
+
loader.load { |file, category| parse(file, category: category) }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def published
|
|
32
|
+
@published ||= all.select(&:published?)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def categories
|
|
36
|
+
@md_record_categories.map do |key, config|
|
|
37
|
+
Category.new(
|
|
38
|
+
key: key,
|
|
39
|
+
name: config[:name],
|
|
40
|
+
position: config[:position]
|
|
41
|
+
)
|
|
42
|
+
end.sort_by(&:position)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def category?(other)
|
|
47
|
+
key = other.is_a?(Category) ? other.key : other
|
|
48
|
+
category == key
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def category_name
|
|
52
|
+
self.class.instance_variable_get(:@md_record_categories).dig(category, :name) || category.to_s.tr("-_", " ").capitalize
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MdRecord
|
|
4
|
+
class CategorizedLoader
|
|
5
|
+
def initialize(path:, categories:)
|
|
6
|
+
@path = Pathname.new(path).expand_path
|
|
7
|
+
@categories = categories
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def load
|
|
11
|
+
@categories.keys.flat_map do |category|
|
|
12
|
+
if category_path(category).directory?
|
|
13
|
+
category_files(category).map { |file| yield file, category }
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def category_files(category)
|
|
21
|
+
Dir.glob(category_path(category).join("*.md"))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def category_path(category)
|
|
25
|
+
@path.join(category.to_s)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MdRecord
|
|
4
|
+
class Category
|
|
5
|
+
attr_reader :key, :name, :position
|
|
6
|
+
|
|
7
|
+
def initialize(key:, name:, position:)
|
|
8
|
+
@key = key
|
|
9
|
+
@name = name
|
|
10
|
+
@position = position
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_param
|
|
14
|
+
key
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "date"
|
|
4
|
+
|
|
5
|
+
module MdRecord
|
|
6
|
+
class FrontmatterParser
|
|
7
|
+
attr_reader :file_path, :frontmatter, :markdown_content
|
|
8
|
+
|
|
9
|
+
def initialize(file_path)
|
|
10
|
+
@file_path = file_path
|
|
11
|
+
@frontmatter = {}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def slug
|
|
15
|
+
File.basename(file_path, ".md")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def title
|
|
19
|
+
frontmatter.fetch("title", slug.titleize)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def content
|
|
23
|
+
markdown_content || raw_content
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def published
|
|
27
|
+
frontmatter.fetch("published", false)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def parse!
|
|
31
|
+
parse_frontmatter!
|
|
32
|
+
self
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def raw_content
|
|
38
|
+
@raw_content ||= File.read(file_path)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def parse_frontmatter!
|
|
42
|
+
if raw_content =~ /\A---\s*\n(.*?)\n---\s*\n(.*)\z/m
|
|
43
|
+
@frontmatter = YAML.safe_load($1, permitted_classes: [Date, Time])
|
|
44
|
+
@markdown_content = $2
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MdRecord
|
|
4
|
+
class Loader
|
|
5
|
+
def initialize(path:)
|
|
6
|
+
@path = Pathname.new(path).expand_path
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def load
|
|
10
|
+
markdown_files.map { |file| yield file }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def markdown_files
|
|
16
|
+
Dir.glob(@path.join("*.md"))
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "erb"
|
|
4
|
+
|
|
5
|
+
module MdRecord
|
|
6
|
+
class MarkdownRenderer < Redcarpet::Render::HTML
|
|
7
|
+
def image(src, title, alt_text)
|
|
8
|
+
if src && !src.start_with?("http://", "https://", "/")
|
|
9
|
+
src = resolve_asset_path(src)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
title_attr = title && !title.empty? ? %( title="#{title}") : ""
|
|
13
|
+
%(<img src="#{src}" alt="#{alt_text}"#{title_attr}>)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def block_code(code, language)
|
|
17
|
+
%(<pre><code>#{ERB::Util.html_escape(code)}</code></pre>)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def resolve_asset_path(src)
|
|
23
|
+
if defined?(ActionController::Base)
|
|
24
|
+
ActionController::Base.helpers.asset_path(src)
|
|
25
|
+
else
|
|
26
|
+
src
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MdRecord
|
|
4
|
+
class RecordNotFound < StandardError
|
|
5
|
+
attr_reader :model, :slug
|
|
6
|
+
|
|
7
|
+
def initialize(message = nil, model: nil, slug: nil)
|
|
8
|
+
@model = model
|
|
9
|
+
@slug = slug
|
|
10
|
+
super(message || default_message)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def default_message
|
|
16
|
+
if model && slug
|
|
17
|
+
"Couldn't find #{model} with slug '#{slug}'"
|
|
18
|
+
elsif model
|
|
19
|
+
"Couldn't find #{model}"
|
|
20
|
+
else
|
|
21
|
+
"Record not found"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/md_record.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_model"
|
|
4
|
+
require "active_support/concern"
|
|
5
|
+
require "redcarpet"
|
|
6
|
+
require "yaml"
|
|
7
|
+
require "pathname"
|
|
8
|
+
|
|
9
|
+
require_relative "md_record/version"
|
|
10
|
+
require_relative "md_record/record_not_found"
|
|
11
|
+
require_relative "md_record/frontmatter_parser"
|
|
12
|
+
require_relative "md_record/markdown_renderer"
|
|
13
|
+
require_relative "md_record/loader"
|
|
14
|
+
require_relative "md_record/categorized_loader"
|
|
15
|
+
require_relative "md_record/category"
|
|
16
|
+
require_relative "md_record/base"
|
|
17
|
+
require_relative "md_record/categorizable"
|
|
18
|
+
|
|
19
|
+
require_relative "md_record/railtie" if defined?(Rails::Railtie)
|
|
20
|
+
|
|
21
|
+
module MdRecord
|
|
22
|
+
end
|
data/md_record.gemspec
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/md_record/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "md_record"
|
|
7
|
+
spec.version = MdRecord::VERSION
|
|
8
|
+
spec.authors = ["Benito Serna"]
|
|
9
|
+
spec.email = ["bhserna@gmail.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "File-backed models for Rails"
|
|
12
|
+
spec.description = "ActiveRecord-like interface for markdown files with YAML frontmatter"
|
|
13
|
+
spec.homepage = "https://github.com/bhserna/md_record"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
spec.required_ruby_version = ">= 3.0"
|
|
16
|
+
|
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
18
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
|
19
|
+
|
|
20
|
+
spec.files = Dir.chdir(__dir__) do
|
|
21
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
22
|
+
(File.expand_path(f) == __FILE__) ||
|
|
23
|
+
f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile])
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
spec.require_paths = ["lib"]
|
|
27
|
+
|
|
28
|
+
spec.add_dependency "activemodel", ">= 7.0"
|
|
29
|
+
spec.add_dependency "activesupport", ">= 7.0"
|
|
30
|
+
spec.add_dependency "redcarpet", ">= 3.0"
|
|
31
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: md_record
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Benito Serna
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2025-12-29 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: activemodel
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '7.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '7.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: activesupport
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '7.0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '7.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: redcarpet
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3.0'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '3.0'
|
|
55
|
+
description: ActiveRecord-like interface for markdown files with YAML frontmatter
|
|
56
|
+
email:
|
|
57
|
+
- bhserna@gmail.com
|
|
58
|
+
executables: []
|
|
59
|
+
extensions: []
|
|
60
|
+
extra_rdoc_files: []
|
|
61
|
+
files:
|
|
62
|
+
- LICENSE.txt
|
|
63
|
+
- README.md
|
|
64
|
+
- Rakefile
|
|
65
|
+
- lib/md_record.rb
|
|
66
|
+
- lib/md_record/base.rb
|
|
67
|
+
- lib/md_record/categorizable.rb
|
|
68
|
+
- lib/md_record/categorized_loader.rb
|
|
69
|
+
- lib/md_record/category.rb
|
|
70
|
+
- lib/md_record/frontmatter_parser.rb
|
|
71
|
+
- lib/md_record/loader.rb
|
|
72
|
+
- lib/md_record/markdown_renderer.rb
|
|
73
|
+
- lib/md_record/railtie.rb
|
|
74
|
+
- lib/md_record/record_not_found.rb
|
|
75
|
+
- lib/md_record/version.rb
|
|
76
|
+
- md_record.gemspec
|
|
77
|
+
homepage: https://github.com/bhserna/md_record
|
|
78
|
+
licenses:
|
|
79
|
+
- MIT
|
|
80
|
+
metadata:
|
|
81
|
+
homepage_uri: https://github.com/bhserna/md_record
|
|
82
|
+
source_code_uri: https://github.com/bhserna/md_record
|
|
83
|
+
post_install_message:
|
|
84
|
+
rdoc_options: []
|
|
85
|
+
require_paths:
|
|
86
|
+
- lib
|
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
88
|
+
requirements:
|
|
89
|
+
- - ">="
|
|
90
|
+
- !ruby/object:Gem::Version
|
|
91
|
+
version: '3.0'
|
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
requirements: []
|
|
98
|
+
rubygems_version: 3.5.22
|
|
99
|
+
signing_key:
|
|
100
|
+
specification_version: 4
|
|
101
|
+
summary: File-backed models for Rails
|
|
102
|
+
test_files: []
|