perron 0.17.0 → 0.18.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +25 -2
  4. data/app/controllers/perron/searches_controller.rb +48 -0
  5. data/app/helpers/perron/feeds_helper.rb +7 -0
  6. data/app/helpers/perron/markdown_helper.rb +3 -3
  7. data/app/helpers/perron/meta_tags_helper.rb +17 -0
  8. data/bin/release +19 -4
  9. data/lib/generators/perron/templates/README.md.tt +31 -7
  10. data/lib/generators/perron/templates/initializer.rb.tt +8 -4
  11. data/lib/generators/rails/content/USAGE +28 -26
  12. data/lib/generators/rails/content/content_generator.rb +6 -7
  13. data/lib/generators/rails/content/templates/controller.rb.tt +1 -5
  14. data/lib/generators/rails/content/templates/model.rb.tt +3 -3
  15. data/lib/perron/collection.rb +10 -1
  16. data/lib/perron/configuration.rb +9 -4
  17. data/lib/perron/content/data.rb +6 -2
  18. data/lib/perron/data_source/class_methods.rb +58 -0
  19. data/lib/perron/data_source/helper_context.rb +20 -0
  20. data/lib/perron/data_source/item.rb +37 -0
  21. data/lib/perron/{data → data_source}/proxy.rb +1 -1
  22. data/lib/perron/data_source.rb +155 -0
  23. data/lib/perron/engine.rb +12 -0
  24. data/lib/perron/html_processor/syntax_highlight.rb +2 -0
  25. data/lib/perron/output_server.rb +7 -2
  26. data/lib/perron/relation.rb +51 -0
  27. data/lib/perron/resource/associations.rb +2 -2
  28. data/lib/perron/resource/class_methods.rb +10 -0
  29. data/lib/perron/resource/configuration.rb +8 -11
  30. data/lib/perron/resource/core.rb +11 -0
  31. data/lib/perron/resource/related/stop_words.rb +20 -20
  32. data/lib/perron/resource/related.rb +73 -52
  33. data/lib/perron/resource/scopes.rb +29 -0
  34. data/lib/perron/resource/searchable.rb +19 -0
  35. data/lib/perron/resource/sourceable.rb +2 -2
  36. data/lib/perron/resource/sweeper.rb +45 -0
  37. data/lib/perron/resource/table_of_content.rb +0 -18
  38. data/lib/perron/resource.rb +30 -20
  39. data/lib/perron/site.rb +3 -3
  40. data/lib/perron/tasks/build.rake +8 -1
  41. data/lib/perron/version.rb +1 -1
  42. data/lib/perron.rb +1 -0
  43. data/perron.gemspec +1 -0
  44. metadata +28 -6
  45. data/app/helpers/feeds_helper.rb +0 -5
  46. data/app/helpers/meta_tags_helper.rb +0 -15
  47. data/lib/perron/data.rb +0 -180
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fbf1b0d5483938df7b88423f3ecd72bffaf938eadcc49a3001a34fcb0156dfb9
4
- data.tar.gz: cd8871c7ef91a102a45bcebbcdc8bbf385db3a83ffb34948cd0d3e49c14d8237
3
+ metadata.gz: 4b7d197a1f26d5fae6c488fe7be6aef6c3818e408d97b5d789f46111db3207be
4
+ data.tar.gz: 0cb809db9260c8e5ded0626f9d790dfb003b937892c1bbce022bcbdac3e5053d
5
5
  SHA512:
6
- metadata.gz: 4d21cfbf61b54fb704990a23cbbf73285364e37ab722246c0202ecea37616398edcfe3fc9f841bc3cae9100108cb61e37200780c0e0ef667515f6e27319498e4
7
- data.tar.gz: bed9e2b68bf2a5697a72a6b3bcb2dfcdb6898b93e31b6bc68b169583462d9e4a4f3e345dec8470077b2566dd31860e8ca97ce83cd82b8a01aff889ad0d5a7d14
6
+ metadata.gz: cc876ae9e8fb6daf1c6496c381efc05eba46fe5bbff9174502480488c34a4dbf5c94d9a360752942a53c395d7df6cb3b9e8342936e8e795b3ab3ccc20f6b3cdd
7
+ data.tar.gz: 99681d91d5d5ea2ffb8488ba4c93c27b2115aebde8132d6f0c8376a6b3e7819c62aef196b424e244af04d8ada7a12080c181cd0f44cf9d52c79125263c3f849b
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ source "https://rubygems.org"
4
4
 
5
5
  gemspec
6
6
 
7
- gem "rails", "~> 7.2.0"
7
+ gem "appraisal"
8
8
 
9
9
  group :development do
10
10
  gem "standard", "~> 1.50.0"
data/Gemfile.lock CHANGED
@@ -1,9 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- perron (0.17.0)
4
+ perron (0.18.0)
5
5
  csv
6
6
  json
7
+ mata (~> 0.8.0)
7
8
  psych
8
9
  rails (>= 7.2.0)
9
10
 
@@ -81,6 +82,10 @@ GEM
81
82
  minitest (>= 5.1)
82
83
  securerandom (>= 0.3)
83
84
  tzinfo (~> 2.0, >= 2.0.5)
85
+ appraisal (2.5.0)
86
+ bundler
87
+ rake
88
+ thor (>= 0.14.0)
84
89
  ast (2.4.3)
85
90
  base64 (0.3.0)
86
91
  benchmark (0.4.1)
@@ -97,6 +102,14 @@ GEM
97
102
  drb (2.2.3)
98
103
  erb (5.0.1)
99
104
  erubi (1.13.1)
105
+ ffi (1.17.3-aarch64-linux-gnu)
106
+ ffi (1.17.3-aarch64-linux-musl)
107
+ ffi (1.17.3-arm-linux-gnu)
108
+ ffi (1.17.3-arm-linux-musl)
109
+ ffi (1.17.3-arm64-darwin)
110
+ ffi (1.17.3-x86_64-darwin)
111
+ ffi (1.17.3-x86_64-linux-gnu)
112
+ ffi (1.17.3-x86_64-linux-musl)
100
113
  globalid (1.2.1)
101
114
  activesupport (>= 6.1)
102
115
  i18n (1.14.7)
@@ -109,6 +122,10 @@ GEM
109
122
  json (2.12.2)
110
123
  language_server-protocol (3.17.0.5)
111
124
  lint_roller (1.1.0)
125
+ listen (3.10.0)
126
+ logger
127
+ rb-fsevent (~> 0.10, >= 0.10.3)
128
+ rb-inotify (~> 0.9, >= 0.9.10)
112
129
  logger (1.7.0)
113
130
  loofah (2.24.1)
114
131
  crass (~> 1.0.2)
@@ -119,6 +136,9 @@ GEM
119
136
  net-pop
120
137
  net-smtp
121
138
  marcel (1.0.4)
139
+ mata (0.8.0)
140
+ listen (~> 3.0)
141
+ rack (>= 3.0)
122
142
  mini_mime (1.1.5)
123
143
  mini_portile2 (2.8.9)
124
144
  minitest (5.27.0)
@@ -202,6 +222,9 @@ GEM
202
222
  zeitwerk (~> 2.6)
203
223
  rainbow (3.1.1)
204
224
  rake (13.3.0)
225
+ rb-fsevent (0.11.2)
226
+ rb-inotify (0.11.1)
227
+ ffi (~> 1.0)
205
228
  rdoc (6.14.2)
206
229
  erb
207
230
  psych (>= 4.0.0)
@@ -267,10 +290,10 @@ PLATFORMS
267
290
  x86_64-linux-musl
268
291
 
269
292
  DEPENDENCIES
293
+ appraisal
270
294
  debug (~> 1.11.0)
271
295
  minitest (~> 5.25, >= 5.25.5)
272
296
  perron!
273
- rails (~> 7.2.0)
274
297
  rake (~> 13.3.0)
275
298
  rouge (~> 4.6.0)
276
299
  standard (~> 1.50.0)
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perron
4
+ class SearchesController < ApplicationController
5
+ before_action :force_json, only: %w[show]
6
+
7
+ def show
8
+ resources = search_scope.flat_map(&:all)
9
+ index = resources.map do |resource|
10
+ base_fields(resource).merge(additional_search_fields(resource))
11
+ end
12
+
13
+ render json: index
14
+ end
15
+
16
+ private
17
+
18
+ def force_json
19
+ request.format = :json
20
+ end
21
+
22
+ def search_scope
23
+ Perron
24
+ .configuration
25
+ .search_scope
26
+ .map { "Content::#{it.classify}".safe_constantize }
27
+ .compact_blank
28
+ end
29
+
30
+ def base_fields(resource)
31
+ {
32
+ slug: polymorphic_path(resource),
33
+ href: polymorphic_path(resource),
34
+ title: resource.try(:title) || resource.metadata.title,
35
+ headings: resource.extracted_headings.flatten.join(" "),
36
+ body: resource.sweeped_content
37
+ }
38
+ end
39
+
40
+ def additional_search_fields(resource)
41
+ return {} unless resource.class.search_fields_list.any?
42
+
43
+ resource.class.search_fields_list.to_h do |field|
44
+ [field, resource.public_send(field)]
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perron
4
+ module FeedsHelper
5
+ def feeds(options = {}) = Perron::Feeds.new.render(options)
6
+ end
7
+ end
@@ -4,10 +4,10 @@ require "perron/markdown"
4
4
 
5
5
  module Perron
6
6
  module MarkdownHelper
7
- def markdownify(content = nil, options = {}, &block)
8
- processors = options.fetch(:process, [])
7
+ def markdownify(content = nil, process: [], &block)
8
+ text = block_given? ? capture(&block).strip_heredoc : content
9
9
 
10
- Perron::Markdown.render(content || capture(&block).strip_heredoc, processors: processors)
10
+ Perron::Markdown.render(text, processors: process)
11
11
  end
12
12
  end
13
13
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perron
4
+ module MetaTagsHelper
5
+ def meta_tags(options = {}) = Perron::Metatags.new(resource.metadata).render(options)
6
+
7
+ private
8
+
9
+ Resource = Data.define(:path, :collection, :metadata, :published_at)
10
+
11
+ def resource
12
+ return Resource.new(request.path, nil, @metadata, nil) if @metadata.present?
13
+
14
+ @resource || Resource.new(request.path, nil, {}, nil)
15
+ end
16
+ end
17
+ end
data/bin/release CHANGED
@@ -3,17 +3,32 @@
3
3
  VERSION=$1
4
4
 
5
5
  if [ -z "$VERSION" ]; then
6
- echo "Error: The version number is required."
7
- echo "Usage: $0 <version-number>"
6
+ echo "Error: Version number or bump type is required"
7
+ echo " Usage: $0 <major|minor|patch|version-number>"
8
+
8
9
  exit 1
9
10
  fi
10
11
 
12
+ if [[ "$VERSION" =~ ^(major|minor|patch)$ ]]; then
13
+ CURRENT=$(grep -o '"[^"]*"' ./lib/perron/version.rb | tr -d '"')
14
+ IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT"
15
+
16
+ case $VERSION in
17
+ major) VERSION="$((MAJOR + 1)).0.0" ;;
18
+ minor) VERSION="$MAJOR.$((MINOR + 1)).0" ;;
19
+ patch) VERSION="$MAJOR.$MINOR.$((PATCH + 1))" ;;
20
+ esac
21
+ fi
22
+
11
23
  printf "module Perron\n VERSION = \"$VERSION\"\nend\n" > ./lib/perron/version.rb
24
+
12
25
  bundle
26
+
13
27
  git add Gemfile.lock lib/perron/version.rb
14
28
  git commit -m "Bump version for $VERSION"
15
29
  git push
16
30
  git tag v$VERSION
17
31
  git push --tags
18
- gem build perron.gemspec
19
- gem push "perron-$VERSION.gem"
32
+
33
+ bundle exec rake build
34
+ gem push "pkg/perron-$VERSION.gem"
@@ -1,22 +1,24 @@
1
1
  # Data
2
2
 
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.
3
+ Perron can consume structured data from YML, JSON or CSV files, making them available within views. This is useful for populating features, team members or any other repeated data structure.
4
4
 
5
5
 
6
6
  ## Usage
7
7
 
8
- To use a data file, instantiate `Perron::Site.data` with the basename of the file and iterate over the result.
8
+ Access data sources using the `Content::Data` namespace with the class name matching the file's basename:
9
9
  ```erb
10
- <%% Perron::Site.data.features.each do |feature| %>
10
+ <%% Content::Data::Features.all.each do |feature| %>
11
11
  <h4><%%= feature.name %></h4>
12
12
  <p><%%= feature.description %></p>
13
13
  <%% end %>
14
14
  ```
15
15
 
16
+ Look up a single entry with `Content::Data::Features.find("advanced-search")`, where `"advanced-search"` matches the value of the entry's `id` field.
17
+
16
18
 
17
19
  ## File location and formats
18
20
 
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")`.
21
+ 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`. Provide a path to any data resource in `/app/content/data/`, via `Content::Data.new("path/to/data-resource")`.
20
22
 
21
23
 
22
24
  ## Accessing data
@@ -30,12 +32,12 @@ feature[:name]
30
32
 
31
33
  ## Rendering
32
34
 
33
- You can render data collections directly using Rails-like partial rendering. When you call `render` on a data collection, Perron will automatically render a partial for each item.
35
+ Render data collections directly using Rails-like partial rendering:
34
36
  ```erb
35
- <%%= render Perron::Site.data.features %>
37
+ <%%= render Content::Data::Features.all %>
36
38
  ```
37
39
 
38
- This expects a partial at `app/views/content/features/_feature.html.erb` that will be rendered once for each feature in your data file. The individual record is made available as a local variable matching the singular form of the collection name.
40
+ This expects a partial at `app/views/content/features/_feature.html.erb` that will be rendered once for each item in `Content::Data::Features.all`. The individual record is made available as a local variable matching the singular form of the collection name.
39
41
  ```erb
40
42
  <!-- app/views/content/features/_feature.html.erb -->
41
43
  <div class="feature">
@@ -43,3 +45,25 @@ This expects a partial at `app/views/content/features/_feature.html.erb` that wi
43
45
  <p><%%= feature.description %></p>
44
46
  </div>
45
47
  ```
48
+
49
+
50
+ ## Data structure
51
+
52
+ Data resources must contain an array of objects. Each record should include an `id` field if used with [associations](/docs/resources/#associations) or with the `find` method:
53
+ ```yaml
54
+ # app/content/data/authors.yml
55
+ - id: rails-designer
56
+ name: Rails Designer
57
+ bio: Creator of Perron
58
+
59
+ - id: cam
60
+ name: Cam
61
+ bio: Contributing author
62
+ ```
63
+
64
+
65
+ ## Enumerable methods
66
+
67
+ [!label v0.17.0+]
68
+
69
+ All data objects support enumerable methods like `select`, `sort_by`, `first` and `count`. See [Enumerable methods](/docs/rendering/#enumerable-methods) for the full list of available methods.
@@ -1,16 +1,20 @@
1
1
  Perron.configure do |config|
2
- # View all options: https://perron.railsdesigner.com/docs/configuration/
2
+ # For all options check out:
3
+ # https://perron.railsdesigner.com/docs/configuration/
3
4
 
4
- # config.site_name = "Chirp Form"
5
-
6
- # The build mode for Perron. Can be :standalone (SSG) or :integrated (alongside your Rails app)
5
+ # The build mode for Perron. Can be :standalone (SSG, default) or :integrated (alongside your Rails app)
7
6
  # config.mode = :standalone
8
7
 
8
+ # Enable Live Reload with DOM Morphing in development
9
+ # config.live_reload = true
10
+
9
11
  # config.default_url_options = {host: "chirpform.com", protocol: "https", trailing_slash: true}
10
12
 
11
13
  # The options hash is passed directly to the chosen library
12
14
  # config.markdown_options = {}
13
15
 
16
+ # config.site_name = "Chirp Form"
17
+
14
18
  # Set meta title suffix
15
19
  # config.metadata.title_suffix = nil
16
20
  # config.metadata.title_separator = " — "
@@ -2,63 +2,65 @@ Description:
2
2
  Generates content model scaffold (controller, views, routes) or creates
3
3
  new content files from templates.
4
4
 
5
+ Arguments:
6
+ NAME Name of the content model (singular or plural)
7
+ actions Actions to generate (default: index show)
8
+
9
+ Options:
10
+ --new [TITLE] Create new content file instead of scaffold
11
+ --data [SOURCE...] Create data source files (default extension: .yml)
12
+ --force-plural Use plural form for model name and class
13
+ --[no-]include-root Include root action and route
14
+ (default: true for pages, false otherwise)
15
+
5
16
  Examples:
6
- Generate content scaffold:
17
+ Generate basic content scaffold:
7
18
  rails generate content Post
8
19
  rails generate content Post index
9
20
  rails generate content Post index show
10
21
 
11
- This will create:
22
+ Creates:
12
23
  app/content/posts/
13
24
  app/models/content/post.rb
14
25
  app/controllers/content/posts_controller.rb
15
26
  app/views/content/posts/index.html.erb
16
27
  app/views/content/posts/show.html.erb
17
28
 
18
- And adds: resources :posts, module: :content, only: %w[index show]
29
+ Adds route:
30
+ resources :posts, module: :content, only: %w[index show]
19
31
 
20
32
  Generate pages scaffold with root:
21
33
  rails generate content Page
22
34
 
23
- This will additionally create:
35
+ Additionally creates:
24
36
  app/content/pages/root.erb
25
- def root action in Content::PagesController
26
- root route in config/routes.rb (if not already defined)
37
+ root action in app/controllers/content/pages_controller.rb
38
+ root route in config/routes.rb
27
39
 
28
- Skip root generation for pages:
40
+ Control root generation:
29
41
  rails generate content Page --no-include-root
30
-
31
- Include root for non-pages content:
32
42
  rails generate content Article --include-root
33
43
 
34
- Generate content scaffold with data sources:
44
+ Generate scaffold with data sources:
35
45
  rails generate content Product --data countries products
36
46
  rails generate content Product --data countries.json products.yml
37
47
 
38
- This will additionally create data source files in app/content/products/
39
- and add sources/template_source class methods to the model.
48
+ Creates data source files in app/content/data/ and adds
49
+ .sources and .template_source class methods to the model.
50
+
51
+ Adds .sources and .template_source class methods to model.
40
52
 
41
53
  Create new content file from template:
42
54
  rails generate content Post --new
43
55
  rails generate content Post --new "My First Post"
44
56
 
45
- This will create a new content file in app/content/posts/ using:
46
- - YYYY-MM-DD-template.*.tt (if exists, with date prefix)
47
- - template.*.tt (if exists, without date prefix)
48
- - Empty file with frontmatter dashes (if no template)
57
+ Creates a new content file in app/content/posts/ using:
58
+ 1. YYYY-MM-DD-template.*.tt (if exists, with date prefix)
59
+ 2. template.*.tt (if exists, without date prefix)
60
+ 3. Empty file with frontmatter dashes (if no template)
49
61
 
50
62
  Template files support ERB:
51
63
  ---
52
64
  title: <%= @title %>
53
65
  published_at: <%= Time.current %>
54
66
  ---
55
-
56
- Arguments:
57
- NAME: Name of the content model (singular or plural)
58
- actions: Actions to generate (default: index show)
59
-
60
- Options:
61
- --new [TITLE]: Create new content file instead of scaffold
62
- --data [source1(.ext) source2(.ext)]: Create data source files (default extension: .yml)
63
- --force-plural: Use plural form for model name and class
64
- --[no-]include-root: Include root action and route (default: true for pages, false otherwise)
@@ -76,7 +76,7 @@ module Rails
76
76
  options[:data].each do |source|
77
77
  name, extension = source.split(".", 2)
78
78
 
79
- create_file File.join(content_directory, "#{name}.#{extension || "yml"}"), ""
79
+ create_file File.join("app", "content", "data", "#{name}.#{extension || "yml"}"), ""
80
80
  end
81
81
  end
82
82
 
@@ -85,13 +85,12 @@ module Rails
85
85
  return unless should_include_root?
86
86
 
87
87
  inject_into_class "app/controllers/content/#{plural_file_name}_controller.rb", "Content::#{plural_class_name}Controller" do
88
- <<-RUBY
88
+ <<~RUBY
89
+ def root
90
+ @resource = Content::#{class_name}.root
89
91
 
90
- def root
91
- @resource = Content::#{class_name}.root
92
-
93
- render :show
94
- end
92
+ render :show
93
+ end
95
94
  RUBY
96
95
  end
97
96
  end
@@ -1,8 +1,4 @@
1
1
  class Content::<%= plural_class_name %>Controller < ApplicationController
2
- <%- if pages_controller? -%>
3
- include Perron::Root
4
- <%- end -%>
5
-
6
2
  <%- if actions.include?("index") -%>
7
3
  def index
8
4
  @resources = Content::<%= class_name %>.all
@@ -11,7 +7,7 @@ class Content::<%= plural_class_name %>Controller < ApplicationController
11
7
  <%- end -%>
12
8
  <%- if actions.include?("show") -%>
13
9
  def show
14
- @resource = Content::<%= class_name %>.find(params[:id])
10
+ @resource = Content::<%= class_name %>.find!(params[:id])
15
11
  end
16
12
  <%- end -%>
17
13
  end
@@ -1,13 +1,13 @@
1
1
  class Content::<%= class_name %> < Perron::Resource
2
2
  <% if data_sources? -%>
3
-
4
3
  sources <%= data_sources.map { ":#{it}" }.join(", ") %>
5
4
 
6
5
  def self.source_template(sources)
7
- <<~TEMPLATE
6
+ <<~MARKDOWN
8
7
  ---
9
8
  ---
10
- TEMPLATE
9
+
10
+ MARKDOWN
11
11
  end
12
12
  <% end -%>
13
13
  end
@@ -16,11 +16,20 @@ module Perron
16
16
  end
17
17
 
18
18
  def all(resource_class = "Content::#{name.classify}".safe_constantize)
19
- load_resources(resource_class).select(&:published?)
19
+ Perron::Relation.new(load_resources(resource_class).select(&:published?))
20
20
  end
21
21
  alias_method :resources, :all
22
22
 
23
23
  def find(slug, resource_class = Resource)
24
+ Perron.deprecator.deprecation_warning(
25
+ :find,
26
+ "Collection#find will return nil instead of raising in the next major version. Use #find! to raise an error."
27
+ )
28
+
29
+ find!(slug, resource_class)
30
+ end
31
+
32
+ def find!(slug, resource_class = Resource)
24
33
  resource = load_resources(resource_class).find { it.slug == slug }
25
34
 
26
35
  return resource if resource
@@ -13,17 +13,17 @@ module Perron
13
13
  def initialize
14
14
  @config = ActiveSupport::OrderedOptions.new
15
15
 
16
- @config.site_name = nil
17
- @config.site_description = nil
18
-
19
16
  @config.output = "output"
20
17
 
21
18
  @config.mode = :standalone
22
19
 
23
- @config.allowed_extensions = %w[erb md]
20
+ @config.live_reload = false
21
+ @config.live_reload_watch_paths = %w[app/content app/views app/assets]
22
+ @config.live_reload_skip_paths = %w[app/assets/builds]
24
23
 
25
24
  @config.exclude_from_public = %w[assets storage]
26
25
  @config.excluded_assets = %w[action_cable actioncable actiontext activestorage rails-ujs trix turbo]
26
+ @config.allowed_extensions = %w[erb md]
27
27
 
28
28
  @config.view_unpublished = Rails.env.development?
29
29
 
@@ -35,11 +35,16 @@ module Perron
35
35
 
36
36
  @config.markdown_options = {}
37
37
 
38
+ @config.search_scope = []
39
+
38
40
  @config.sitemap = ActiveSupport::OrderedOptions.new
39
41
  @config.sitemap.enabled = false
40
42
  @config.sitemap.priority = 0.5
41
43
  @config.sitemap.change_frequency = :monthly
42
44
 
45
+ @config.site_name = nil
46
+ @config.site_description = nil
47
+
43
48
  @config.metadata = ActiveSupport::OrderedOptions.new
44
49
  @config.metadata.title_separator = " — "
45
50
  end
@@ -2,9 +2,13 @@
2
2
 
3
3
  module Content
4
4
  module Data
5
+ def self.new(identifier)
6
+ Perron::DataSource.new(identifier)
7
+ end
8
+
5
9
  def self.const_missing(name)
6
- klass = Class.new(Perron::Data) do
7
- def self.const_missing(nested_name) = const_set(nested_name, Class.new(Perron::Data))
10
+ klass = Class.new(Perron::DataSource) do
11
+ def self.const_missing(nested_name) = const_set(nested_name, Class.new(Perron::DataSource))
8
12
  end
9
13
 
10
14
  const_set(name, klass)
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perron
4
+ class DataSource < SimpleDelegator
5
+ module ClassMethods
6
+ extend ActiveSupport::Concern
7
+
8
+ class_methods do
9
+ def all
10
+ parts = name.to_s.split("::").drop(2)
11
+ identifier = parts.empty? ? name.demodulize.underscore : parts.map(&:underscore).join("/")
12
+
13
+ new(identifier)
14
+ end
15
+
16
+ def find(id)
17
+ all.find { it[:id] == id || it["id"] == id }
18
+ end
19
+
20
+ def count = all.size
21
+
22
+ def first = all.first
23
+
24
+ def second = all[1]
25
+
26
+ def third = all[2]
27
+
28
+ def fourth = all[3]
29
+
30
+ def fifth = all[4]
31
+
32
+ def forty_two = all[41]
33
+
34
+ def last = all.last
35
+
36
+ def take(n) = all.first(n)
37
+
38
+ def path_for(identifier)
39
+ path = Pathname.new(identifier)
40
+
41
+ return path.to_s if path.file? && path.absolute?
42
+
43
+ base_path = Rails.root.join("app", "content", "data")
44
+
45
+ SUPPORTED_EXTENSIONS.lazy.map { base_path.join("#{identifier}#{it}") }.find(&:exist?)&.to_s
46
+ end
47
+
48
+ def path_for!(identifier)
49
+ path_for(identifier).tap do |path|
50
+ raise Errors::FileNotFoundError, "No data file found for `#{identifier}`" unless path
51
+ end
52
+ end
53
+
54
+ def directory?(identifier) = Dir.exist?(Rails.root.join("app", "content", "data", identifier))
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perron
4
+ class DataSource < SimpleDelegator
5
+ class HelperContext
6
+ include Singleton
7
+
8
+ def initialize
9
+ self.class.include ActionView::Helpers::AssetUrlHelper
10
+ self.class.include ActionView::Helpers::DateHelper
11
+ self.class.include Rails.application.routes.url_helpers
12
+ end
13
+
14
+ def get_binding = binding
15
+
16
+ def default_url_options = Perron.configuration.default_url_options || {}
17
+ end
18
+ private_constant :HelperContext
19
+ end
20
+ end