perron 0.13.3 → 0.14.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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/lib/generators/perron/templates/README.md.tt +5 -17
- data/lib/generators/perron/templates/initializer.rb.tt +3 -3
- data/lib/perron/engine.rb +1 -0
- data/lib/perron/markdown.rb +51 -21
- data/lib/perron/resource/associations.rb +69 -0
- data/lib/perron/resource/metadata.rb +7 -3
- data/lib/perron/resource/reading_time.rb +36 -0
- data/lib/perron/resource/sourceable.rb +102 -0
- data/lib/perron/resource.rb +6 -0
- data/lib/perron/site/builder/feeds/json.rb +1 -1
- data/lib/perron/site/builder/feeds/rss.rb +1 -1
- data/lib/perron/site/validate.rb +3 -1
- data/lib/perron/tasks/sync_sources.rake +12 -0
- data/lib/perron/tasks/validate.rake +1 -1
- data/lib/perron/version.rb +1 -1
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '080352c09efb475419f74de6ee7cf01a491d4cc349f6cf0d6e23d35132c83953'
|
|
4
|
+
data.tar.gz: 156c0419afc4c3aa77411ac7f7508cbea56de584d164624be86b4d2615baf7f5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c75e1453c34bf8a8b8a4345d9167110745c1c47d8094aea3345e85fb46de51b0d326c904a7132c20e058ae89156c48dac5b9311121fc0359ad1d348ccde7d27f
|
|
7
|
+
data.tar.gz: a3acd15ee6f0224c032b31dac7272539e6ed6e6c9451a4b22d47c83c108f8fa374f5b6b7ceab97ae7bf4d6cc1296bbac8cd9c8788b28c7187f50c29c4621ee01
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -1,37 +1,25 @@
|
|
|
1
1
|
# Data
|
|
2
2
|
|
|
3
|
-
Perron can consume structured data from YML, JSON, or CSV files, making them available within your templates.
|
|
4
|
-
This is useful for populating features, team members, or any other repeated data structure.
|
|
3
|
+
Perron can consume structured data from YML, JSON, or CSV files, making them available within your templates. This is useful for populating features, team members, or any other repeated data structure.
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
## Usage
|
|
8
7
|
|
|
9
|
-
To use a data file,
|
|
8
|
+
To use a data file, instantiate `Perron::Site.data` with the basename of the file and iterate over the result.
|
|
10
9
|
```erb
|
|
11
10
|
<%% Perron::Site.data.features.each do |feature| %>
|
|
12
11
|
<h4><%%= feature.name %></h4>
|
|
13
|
-
|
|
14
|
-
<p><%%= feature.description %></p>
|
|
15
|
-
<%% end %>
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
This is a convenient shorthand for `Perron::Data.new("features")`, which can also be used directly:
|
|
19
|
-
```ruby
|
|
20
|
-
<%% Perron::Data.new("features").each do |feature| %>
|
|
21
|
-
<h4><%%= feature.name %></h4>
|
|
22
|
-
|
|
23
12
|
<p><%%= feature.description %></p>
|
|
24
13
|
<%% end %>
|
|
25
14
|
```
|
|
26
15
|
|
|
27
16
|
|
|
28
|
-
## File
|
|
17
|
+
## File location and formats
|
|
29
18
|
|
|
30
|
-
By default, Perron looks up `app/content/data/` for files with a `.yml`, `.json`, or `.csv` extension.
|
|
31
|
-
For a `new("features")` call, it would find `features.yml`, `features.json`, or `features.csv`. You can also provide a full, absolute path to any data file, like `Perron::Data.new("path-to-some-data-file")`.
|
|
19
|
+
By default, Perron looks up `app/content/data/` for files with a `.yml`, `.json`, or `.csv` extension. For a `features` call, it would find `features.yml`, `features.json`, or `features.csv`. You can also provide a path to any data file, via `Perron::Data.new("path/to/data.json")`.
|
|
32
20
|
|
|
33
21
|
|
|
34
|
-
## Accessing
|
|
22
|
+
## Accessing data
|
|
35
23
|
|
|
36
24
|
The wrapper object provides flexible, read-only access to each record's attributes. Both dot notation and hash-like key access are supported.
|
|
37
25
|
```ruby
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Perron.configure do |config|
|
|
2
2
|
# config.output = "output"
|
|
3
3
|
|
|
4
|
-
# config.site_name = "
|
|
4
|
+
# config.site_name = "Chirp Form"
|
|
5
5
|
|
|
6
6
|
# The build mode for Perron. Can be :standalone or :integrated
|
|
7
7
|
# config.mode = :standalone
|
|
@@ -16,8 +16,8 @@ Perron.configure do |config|
|
|
|
16
16
|
|
|
17
17
|
# Set default meta values
|
|
18
18
|
# Examples:
|
|
19
|
-
# - `config.metadata.description = "
|
|
20
|
-
# - `config.metadata.author = "
|
|
19
|
+
# - `config.metadata.description = "Add forms to any static site. Display responses anywhere."`
|
|
20
|
+
# - `config.metadata.author = "Chirp Form Team"`
|
|
21
21
|
|
|
22
22
|
# Set meta title suffix
|
|
23
23
|
# config.metadata.title_suffix = nil
|
data/lib/perron/engine.rb
CHANGED
data/lib/perron/markdown.rb
CHANGED
|
@@ -17,39 +17,69 @@ module Perron
|
|
|
17
17
|
@parser ||= markdown_parser
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
def
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
def configured_parser
|
|
21
|
+
return unless (parser_name = Perron.configuration.markdown_parser)
|
|
22
|
+
class_name = parser_name.to_s.camelize
|
|
23
|
+
class_name += "Parser" unless class_name.end_with?("Parser")
|
|
24
|
+
|
|
25
|
+
klass = if const_defined?(class_name)
|
|
26
|
+
const_get(class_name)
|
|
27
|
+
elsif Object.const_defined?(class_name)
|
|
28
|
+
Object.const_get(class_name)
|
|
27
29
|
else
|
|
28
|
-
|
|
30
|
+
raise "Can't find parser #{parser_name} by class name #{class_name}"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
unless klass.available?
|
|
34
|
+
raise "Parser #{parser_name} #{class_name} is not available (gem not installed?)"
|
|
29
35
|
end
|
|
36
|
+
|
|
37
|
+
klass
|
|
30
38
|
end
|
|
31
|
-
end
|
|
32
39
|
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
def available_parser = Parser.descendants.find(&:available?) || Parser
|
|
41
|
+
|
|
42
|
+
def markdown_parser
|
|
43
|
+
(configured_parser || available_parser).new(**Perron.configuration.markdown_options)
|
|
44
|
+
end
|
|
35
45
|
end
|
|
36
46
|
|
|
37
|
-
class
|
|
38
|
-
|
|
47
|
+
class Parser
|
|
48
|
+
attr_reader :options
|
|
49
|
+
|
|
50
|
+
def initialize(**options)
|
|
51
|
+
@options = options
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def parse(text) = text.to_s
|
|
55
|
+
|
|
56
|
+
def self.available? = true
|
|
39
57
|
end
|
|
40
58
|
|
|
41
|
-
class RedcarpetParser
|
|
42
|
-
def
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
markdown = Redcarpet::Markdown.new(renderer, options.fetch(:markdown_options, {}))
|
|
59
|
+
class RedcarpetParser < Parser
|
|
60
|
+
def renderer
|
|
61
|
+
@renderer ||= Redcarpet::Render::HTML.new(options.fetch(:renderer_options, {}))
|
|
62
|
+
end
|
|
46
63
|
|
|
47
|
-
|
|
64
|
+
def markdown
|
|
65
|
+
@markdown ||= Redcarpet::Markdown.new(renderer, options.fetch(:markdown_options, {}))
|
|
48
66
|
end
|
|
67
|
+
|
|
68
|
+
def parse(text) = markdown.render(text)
|
|
69
|
+
|
|
70
|
+
def self.available? = defined?(::Redcarpet)
|
|
49
71
|
end
|
|
50
72
|
|
|
51
|
-
class
|
|
52
|
-
def parse(text) = text.
|
|
73
|
+
class KramdownParser < Parser
|
|
74
|
+
def parse(text) = Kramdown::Document.new(text, options).to_html
|
|
75
|
+
|
|
76
|
+
def self.available? = defined?(::Kramdown)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
class CommonMarkerParser < Parser
|
|
80
|
+
def parse(text) = Commonmarker.to_html(text, **options)
|
|
81
|
+
|
|
82
|
+
def self.available? = defined?(::Commonmarker)
|
|
53
83
|
end
|
|
54
84
|
end
|
|
55
85
|
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Perron
|
|
4
|
+
class Resource
|
|
5
|
+
module Associations
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
class_methods do
|
|
9
|
+
def belongs_to(association_name, **options)
|
|
10
|
+
define_method(association_name) do
|
|
11
|
+
cache_belongs_to_association(association_name) do
|
|
12
|
+
associated_class = association_class_for(association_name, **options)
|
|
13
|
+
foreign_key = foreign_key_for(association_name, **options)
|
|
14
|
+
identifier = metadata[foreign_key]
|
|
15
|
+
|
|
16
|
+
identifier ? associated_class.find(identifier) : nil
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def has_many(association_name, **options)
|
|
22
|
+
define_method(association_name) do
|
|
23
|
+
cache_has_many_association(association_name) do
|
|
24
|
+
associated_class = association_class_for(association_name, singularize: true, **options)
|
|
25
|
+
foreign_key = foreign_key_for(inverse_association_name, **options)
|
|
26
|
+
primary_key_method = options.fetch(:primary_key, :slug)
|
|
27
|
+
lookup_value = public_send(primary_key_method)
|
|
28
|
+
|
|
29
|
+
associated_class.all.select { |record| record.metadata[foreign_key] == lookup_value }
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def cache_belongs_to_association(name)
|
|
38
|
+
@belongs_to_cache ||= {}
|
|
39
|
+
return @belongs_to_cache[name] if @belongs_to_cache.key?(name)
|
|
40
|
+
|
|
41
|
+
@belongs_to_cache[name] = yield
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def cache_has_many_association(name)
|
|
45
|
+
@has_many_cache ||= {}
|
|
46
|
+
return @has_many_cache[name] if @has_many_cache.key?(name)
|
|
47
|
+
|
|
48
|
+
@has_many_cache[name] = yield
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def association_class_for(association_name, singularize: false, **options)
|
|
52
|
+
class_name = options[:class_name] || begin
|
|
53
|
+
name = association_name.to_s
|
|
54
|
+
name = name.singularize if singularize
|
|
55
|
+
|
|
56
|
+
"Content::#{name.classify}"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class_name.constantize
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def foreign_key_for(base_name, **options)
|
|
63
|
+
(options[:foreign_key] || "#{base_name}_id").to_s
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def inverse_association_name = self.class.name.demodulize.underscore
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -49,10 +49,14 @@ module Perron
|
|
|
49
49
|
return @frontmatter[:canonical_url] if @frontmatter[:canonical_url]
|
|
50
50
|
return Rails.application.routes.url_helpers.root_url(**Perron.configuration.default_url_options) if @resource.slug == "/"
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
begin
|
|
53
|
+
Rails.application.routes.url_helpers.polymorphic_url(
|
|
54
|
+
@resource,
|
|
54
55
|
**Perron.configuration.default_url_options
|
|
55
|
-
|
|
56
|
+
)
|
|
57
|
+
rescue
|
|
58
|
+
false
|
|
59
|
+
end
|
|
56
60
|
end
|
|
57
61
|
|
|
58
62
|
def site_data
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Perron
|
|
4
|
+
class Resource
|
|
5
|
+
module ReadingTime
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
def estimated_reading_time(wpm: DEFAULT_WORDS_PER_MINUTE, format: DEFAULT_FORMAT)
|
|
9
|
+
word_count = content.scan(/\b[a-zA-Z]+\b/).size
|
|
10
|
+
total_minutes = [(word_count.to_f / wpm).ceil, 1].max
|
|
11
|
+
|
|
12
|
+
hours = total_minutes / 60
|
|
13
|
+
minutes = total_minutes % 60
|
|
14
|
+
seconds = ((word_count.to_f / wpm) * 60).to_i % 60
|
|
15
|
+
|
|
16
|
+
return total_minutes if format.blank?
|
|
17
|
+
|
|
18
|
+
format % {
|
|
19
|
+
minutes: minutes,
|
|
20
|
+
total_minutes: total_minutes,
|
|
21
|
+
hours: hours,
|
|
22
|
+
seconds: seconds,
|
|
23
|
+
min: minutes,
|
|
24
|
+
h: hours,
|
|
25
|
+
s: seconds
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
alias_method :reading_time, :estimated_reading_time
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
DEFAULT_WORDS_PER_MINUTE = 200
|
|
33
|
+
DEFAULT_FORMAT = "%{minutes} min read"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Perron
|
|
4
|
+
class Resource
|
|
5
|
+
module Sourceable
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
class_methods do
|
|
9
|
+
def sources(*arguments)
|
|
10
|
+
@source_definitions = parsed(*arguments)
|
|
11
|
+
end
|
|
12
|
+
alias_method :source, :sources
|
|
13
|
+
|
|
14
|
+
def source_definitions
|
|
15
|
+
@source_definitions || {}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def source_names = source_definitions.keys
|
|
19
|
+
|
|
20
|
+
def generate_from_sources!
|
|
21
|
+
return unless source_backed?
|
|
22
|
+
|
|
23
|
+
combinations.each do |combo|
|
|
24
|
+
content = content_with combo
|
|
25
|
+
filename = filename_with combo
|
|
26
|
+
|
|
27
|
+
FileUtils.mkdir_p(output_dir)
|
|
28
|
+
File.write(output_dir.join("#{filename}.erb"), content)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def source_backed? = source_names.any?
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def parsed(*arguments)
|
|
37
|
+
return {} if arguments.empty?
|
|
38
|
+
|
|
39
|
+
arguments.flat_map { it.is_a?(Hash) ? it.to_a : [[it, {primary_key: :id}]] }.to_h
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def combinations
|
|
43
|
+
datasets = source_names.map { Perron::Site.data.public_send(it) }
|
|
44
|
+
|
|
45
|
+
datasets.first.product(*datasets[1..])
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def content_with(combo)
|
|
49
|
+
data = source_names.each.with_index.to_h { |name, index| [name, combo[index]] }
|
|
50
|
+
sources = Source.new(data)
|
|
51
|
+
|
|
52
|
+
source_template(sources)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def filename_with(combo)
|
|
56
|
+
source_names.each_with_index.map do |name, index|
|
|
57
|
+
primary_key = source_definitions[name][:primary_key]
|
|
58
|
+
|
|
59
|
+
combo[index].public_send(primary_key)
|
|
60
|
+
end.join("-")
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def output_dir = Perron.configuration.input.join(model_name.collection)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def source_backed? = self.class.source_backed?
|
|
67
|
+
|
|
68
|
+
def sources
|
|
69
|
+
@sources ||= begin
|
|
70
|
+
data = self.class.source_definitions.each_with_object({}) do |(name, options), hash|
|
|
71
|
+
primary_key = options[:primary_key]
|
|
72
|
+
singular_name = name.to_s.singularize
|
|
73
|
+
identifier = frontmatter["#{singular_name}_#{primary_key}"]
|
|
74
|
+
hash[name] = Perron::Site.data.public_send(name).find { it.public_send(primary_key).to_s == identifier.to_s }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
Source.new(data)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def source_template(sources)
|
|
82
|
+
raise NotImplementedError, "#{self.class.name} must implement #source_template"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class Source
|
|
86
|
+
def initialize(data)
|
|
87
|
+
@data = data
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def method_missing(name, *arguments, &block)
|
|
91
|
+
return super if arguments.any? || block
|
|
92
|
+
return @data[name] if @data.key?(name)
|
|
93
|
+
|
|
94
|
+
super
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def respond_to_missing?(name, _) = @data.key?(name)
|
|
98
|
+
end
|
|
99
|
+
private_constant :Source
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
data/lib/perron/resource.rb
CHANGED
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
require "perron/resource/configuration"
|
|
4
4
|
require "perron/resource/core"
|
|
5
5
|
require "perron/resource/class_methods"
|
|
6
|
+
require "perron/resource/associations"
|
|
6
7
|
require "perron/resource/metadata"
|
|
7
8
|
require "perron/resource/publishable"
|
|
9
|
+
require "perron/resource/reading_time"
|
|
8
10
|
require "perron/resource/related"
|
|
9
11
|
require "perron/resource/renderer"
|
|
10
12
|
require "perron/resource/slug"
|
|
11
13
|
require "perron/resource/separator"
|
|
14
|
+
require "perron/resource/sourceable"
|
|
12
15
|
require "perron/resource/table_of_content"
|
|
13
16
|
|
|
14
17
|
module Perron
|
|
@@ -20,6 +23,9 @@ module Perron
|
|
|
20
23
|
include Perron::Resource::Configuration
|
|
21
24
|
include Perron::Resource::Core
|
|
22
25
|
include Perron::Resource::ClassMethods
|
|
26
|
+
include Perron::Resource::Associations
|
|
27
|
+
include Perron::Resource::ReadingTime
|
|
28
|
+
include Perron::Resource::Sourceable
|
|
23
29
|
include Perron::Resource::Publishable
|
|
24
30
|
include Perron::Resource::TableOfContent
|
|
25
31
|
|
|
@@ -25,7 +25,7 @@ module Perron
|
|
|
25
25
|
items: resources.map do |resource|
|
|
26
26
|
{
|
|
27
27
|
id: resource.id,
|
|
28
|
-
url: url.polymorphic_url(resource),
|
|
28
|
+
url: url.polymorphic_url(resource, ref: feed_configuration.ref).delete_suffix("?ref="),
|
|
29
29
|
date_published: resource.published_at&.iso8601,
|
|
30
30
|
title: resource.metadata.title,
|
|
31
31
|
content_html: Perron::Markdown.render(resource.content)
|
|
@@ -27,7 +27,7 @@ module Perron
|
|
|
27
27
|
resources.each do |resource|
|
|
28
28
|
xml.item do
|
|
29
29
|
xml.guid resource.id
|
|
30
|
-
xml.link url.polymorphic_url(resource), isPermaLink: true
|
|
30
|
+
xml.link url.polymorphic_url(resource, ref: feed_configuration.ref).delete_suffix("?ref="), isPermaLink: true
|
|
31
31
|
xml.pubDate(resource.published_at&.rfc822)
|
|
32
32
|
xml.title resource.metadata.title
|
|
33
33
|
xml.description { xml.cdata(Perron::Markdown.render(resource.content)) }
|
data/lib/perron/site/validate.rb
CHANGED
|
@@ -19,11 +19,13 @@ module Perron
|
|
|
19
19
|
|
|
20
20
|
puts [
|
|
21
21
|
"Validation finished",
|
|
22
|
-
(" with #{@failures.count} failures" if
|
|
22
|
+
(" with #{@failures.count} failures" if failed?),
|
|
23
23
|
"."
|
|
24
24
|
].join
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
def failed? = @failures.any?
|
|
28
|
+
|
|
27
29
|
private
|
|
28
30
|
|
|
29
31
|
Failure = ::Data.define(:identifier, :errors)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
namespace :perron do
|
|
2
|
+
desc "Sync source-backed resources"
|
|
3
|
+
task :sync_sources, [:name] => :environment do |_, arguments|
|
|
4
|
+
Rails.application.eager_load!
|
|
5
|
+
|
|
6
|
+
resource_classes = arguments.name ? ["Content::#{arguments.name.classify}".constantize] : Perron::Resource.descendants
|
|
7
|
+
|
|
8
|
+
resource_classes.compact.each do |resource_class|
|
|
9
|
+
resource_class.generate_from_sources! if resource_class.source_backed?
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
data/lib/perron/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: perron
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.14.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rails Designer Developers
|
|
@@ -113,16 +113,19 @@ files:
|
|
|
113
113
|
- lib/perron/metatags.rb
|
|
114
114
|
- lib/perron/refinements/delete_suffixes.rb
|
|
115
115
|
- lib/perron/resource.rb
|
|
116
|
+
- lib/perron/resource/associations.rb
|
|
116
117
|
- lib/perron/resource/class_methods.rb
|
|
117
118
|
- lib/perron/resource/configuration.rb
|
|
118
119
|
- lib/perron/resource/core.rb
|
|
119
120
|
- lib/perron/resource/metadata.rb
|
|
120
121
|
- lib/perron/resource/publishable.rb
|
|
122
|
+
- lib/perron/resource/reading_time.rb
|
|
121
123
|
- lib/perron/resource/related.rb
|
|
122
124
|
- lib/perron/resource/related/stop_words.rb
|
|
123
125
|
- lib/perron/resource/renderer.rb
|
|
124
126
|
- lib/perron/resource/separator.rb
|
|
125
127
|
- lib/perron/resource/slug.rb
|
|
128
|
+
- lib/perron/resource/sourceable.rb
|
|
126
129
|
- lib/perron/resource/table_of_content.rb
|
|
127
130
|
- lib/perron/root.rb
|
|
128
131
|
- lib/perron/site.rb
|
|
@@ -137,6 +140,7 @@ files:
|
|
|
137
140
|
- lib/perron/site/builder/sitemap.rb
|
|
138
141
|
- lib/perron/site/validate.rb
|
|
139
142
|
- lib/perron/tasks/build.rake
|
|
143
|
+
- lib/perron/tasks/sync_sources.rake
|
|
140
144
|
- lib/perron/tasks/validate.rake
|
|
141
145
|
- lib/perron/version.rb
|
|
142
146
|
- perron.gemspec
|