perron 0.17.0 → 1.0.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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +25 -2
  4. data/app/controllers/perron/concierge_controller.rb +13 -0
  5. data/app/controllers/perron/searches_controller.rb +48 -0
  6. data/app/helpers/perron/feeds_helper.rb +7 -0
  7. data/app/helpers/perron/markdown_helper.rb +3 -3
  8. data/app/helpers/perron/meta_tags_helper.rb +17 -0
  9. data/app/views/perron/concierge/show.html.erb +271 -0
  10. data/bin/release +19 -4
  11. data/lib/generators/rails/content/USAGE +45 -26
  12. data/lib/generators/rails/content/content_generator.rb +16 -13
  13. data/lib/generators/rails/content/templates/controller.rb.tt +7 -5
  14. data/lib/generators/rails/content/templates/model.rb.tt +4 -4
  15. data/lib/perron/assets/icon.png +0 -0
  16. data/lib/perron/assets/icon.svg +1 -0
  17. data/lib/perron/collection.rb +10 -1
  18. data/lib/perron/configuration.rb +13 -4
  19. data/lib/perron/content/data.rb +6 -2
  20. data/lib/perron/data_source/class_methods.rb +66 -0
  21. data/lib/perron/data_source/helper_context.rb +20 -0
  22. data/lib/perron/data_source/item.rb +37 -0
  23. data/lib/perron/{data → data_source}/proxy.rb +1 -1
  24. data/lib/perron/data_source.rb +140 -0
  25. data/lib/perron/development_feed_server.rb +69 -0
  26. data/lib/perron/engine.rb +41 -1
  27. data/lib/perron/errors.rb +2 -0
  28. data/lib/perron/feeds.rb +4 -3
  29. data/lib/perron/html_processor/absolute_urls.rb +27 -0
  30. data/lib/perron/html_processor/base.rb +2 -2
  31. data/lib/perron/html_processor.rb +7 -11
  32. data/lib/perron/install/README.md.tt +67 -0
  33. data/lib/{generators/perron/templates → perron/install}/initializer.rb.tt +8 -4
  34. data/lib/perron/install.rb +23 -0
  35. data/lib/perron/markdown.rb +2 -2
  36. data/lib/perron/output_server.rb +16 -2
  37. data/lib/perron/relation.rb +51 -0
  38. data/lib/perron/resource/adjacency.rb +70 -0
  39. data/lib/perron/resource/associations.rb +3 -3
  40. data/lib/perron/resource/class_methods.rb +10 -0
  41. data/lib/perron/resource/configuration.rb +16 -14
  42. data/lib/perron/resource/core.rb +11 -0
  43. data/lib/perron/resource/metadata.rb +10 -1
  44. data/lib/perron/resource/publishable.rb +2 -0
  45. data/lib/perron/resource/related/stop_words.rb +20 -20
  46. data/lib/perron/resource/related.rb +76 -54
  47. data/lib/perron/resource/scopes.rb +29 -0
  48. data/lib/perron/resource/searchable.rb +19 -0
  49. data/lib/perron/resource/sourceable.rb +39 -9
  50. data/lib/perron/resource/sweeper.rb +45 -0
  51. data/lib/perron/resource/table_of_content.rb +0 -18
  52. data/lib/perron/resource.rb +32 -20
  53. data/lib/perron/site/builder/assets.rb +1 -1
  54. data/lib/perron/site/builder/feeds/atom.erb +44 -0
  55. data/lib/perron/site/builder/feeds/atom.rb +41 -0
  56. data/lib/perron/site/builder/feeds/json.erb +19 -0
  57. data/lib/perron/site/builder/feeds/json.rb +7 -33
  58. data/lib/perron/site/builder/feeds/rss.erb +28 -0
  59. data/lib/perron/site/builder/feeds/rss.rb +6 -28
  60. data/lib/perron/site/builder/feeds/template.rb +63 -0
  61. data/lib/perron/site/builder/feeds.rb +8 -3
  62. data/lib/perron/site/builder/paths.rb +58 -14
  63. data/lib/perron/site/builder/route_resources.rb +79 -0
  64. data/lib/perron/site/builder/sitemap.rb +71 -20
  65. data/lib/perron/site/builder.rb +1 -1
  66. data/lib/perron/site/validate.rb +1 -2
  67. data/lib/perron/site.rb +10 -3
  68. data/lib/perron/tasks/build.rake +6 -0
  69. data/lib/perron/tasks/install.rake +12 -0
  70. data/lib/perron/version.rb +1 -1
  71. data/lib/perron.rb +1 -0
  72. data/perron.gemspec +1 -0
  73. metadata +45 -10
  74. data/app/helpers/feeds_helper.rb +0 -5
  75. data/app/helpers/meta_tags_helper.rb +0 -15
  76. data/lib/generators/perron/install_generator.rb +0 -32
  77. data/lib/generators/perron/templates/README.md.tt +0 -45
  78. data/lib/perron/data.rb +0 -180
  79. data/lib/perron/html_processor/syntax_highlight.rb +0 -30
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.17.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rails Designer Developers
@@ -23,6 +23,20 @@ dependencies:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
25
  version: 7.2.0
26
+ - !ruby/object:Gem::Dependency
27
+ name: mata
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: 0.8.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.8.0
26
40
  - !ruby/object:Gem::Dependency
27
41
  name: csv
28
42
  requirement: !ruby/object:Gem::Requirement
@@ -78,17 +92,17 @@ files:
78
92
  - Gemfile.lock
79
93
  - README.md
80
94
  - Rakefile
81
- - app/helpers/feeds_helper.rb
82
- - app/helpers/meta_tags_helper.rb
95
+ - app/controllers/perron/concierge_controller.rb
96
+ - app/controllers/perron/searches_controller.rb
83
97
  - app/helpers/perron/erb_helper.rb
98
+ - app/helpers/perron/feeds_helper.rb
84
99
  - app/helpers/perron/markdown_helper.rb
100
+ - app/helpers/perron/meta_tags_helper.rb
101
+ - app/views/perron/concierge/show.html.erb
85
102
  - bin/console
86
103
  - bin/rails
87
104
  - bin/release
88
105
  - bin/setup
89
- - lib/generators/perron/install_generator.rb
90
- - lib/generators/perron/templates/README.md.tt
91
- - lib/generators/perron/templates/initializer.rb.tt
92
106
  - lib/generators/rails/content/USAGE
93
107
  - lib/generators/rails/content/content_generator.rb
94
108
  - lib/generators/rails/content/templates/controller.rb.tt
@@ -97,25 +111,36 @@ files:
97
111
  - lib/generators/rails/content/templates/root.erb.tt
98
112
  - lib/generators/rails/content/templates/show.html.erb.tt
99
113
  - lib/perron.rb
114
+ - lib/perron/assets/icon.png
115
+ - lib/perron/assets/icon.svg
100
116
  - lib/perron/collection.rb
101
117
  - lib/perron/configuration.rb
102
118
  - lib/perron/content/data.rb
103
- - lib/perron/data.rb
104
- - lib/perron/data/proxy.rb
119
+ - lib/perron/data_source.rb
120
+ - lib/perron/data_source/class_methods.rb
121
+ - lib/perron/data_source/helper_context.rb
122
+ - lib/perron/data_source/item.rb
123
+ - lib/perron/data_source/proxy.rb
105
124
  - lib/perron/deprecator.rb
125
+ - lib/perron/development_feed_server.rb
106
126
  - lib/perron/engine.rb
107
127
  - lib/perron/errors.rb
108
128
  - lib/perron/feeds.rb
109
129
  - lib/perron/html_processor.rb
130
+ - lib/perron/html_processor/absolute_urls.rb
110
131
  - lib/perron/html_processor/base.rb
111
132
  - lib/perron/html_processor/lazy_load_images.rb
112
- - lib/perron/html_processor/syntax_highlight.rb
113
133
  - lib/perron/html_processor/target_blank.rb
134
+ - lib/perron/install.rb
135
+ - lib/perron/install/README.md.tt
136
+ - lib/perron/install/initializer.rb.tt
114
137
  - lib/perron/markdown.rb
115
138
  - lib/perron/metatags.rb
116
139
  - lib/perron/output_server.rb
117
140
  - lib/perron/refinements/delete_suffixes.rb
141
+ - lib/perron/relation.rb
118
142
  - lib/perron/resource.rb
143
+ - lib/perron/resource/adjacency.rb
119
144
  - lib/perron/resource/associations.rb
120
145
  - lib/perron/resource/class_methods.rb
121
146
  - lib/perron/resource/configuration.rb
@@ -127,25 +152,35 @@ files:
127
152
  - lib/perron/resource/related.rb
128
153
  - lib/perron/resource/related/stop_words.rb
129
154
  - lib/perron/resource/renderer.rb
155
+ - lib/perron/resource/scopes.rb
156
+ - lib/perron/resource/searchable.rb
130
157
  - lib/perron/resource/separator.rb
131
158
  - lib/perron/resource/slug.rb
132
159
  - lib/perron/resource/sourceable.rb
160
+ - lib/perron/resource/sweeper.rb
133
161
  - lib/perron/resource/table_of_content.rb
134
162
  - lib/perron/site.rb
135
163
  - lib/perron/site/builder.rb
136
164
  - lib/perron/site/builder/additional_routes.rb
137
165
  - lib/perron/site/builder/assets.rb
138
166
  - lib/perron/site/builder/feeds.rb
167
+ - lib/perron/site/builder/feeds/atom.erb
168
+ - lib/perron/site/builder/feeds/atom.rb
139
169
  - lib/perron/site/builder/feeds/author.rb
170
+ - lib/perron/site/builder/feeds/json.erb
140
171
  - lib/perron/site/builder/feeds/json.rb
172
+ - lib/perron/site/builder/feeds/rss.erb
141
173
  - lib/perron/site/builder/feeds/rss.rb
174
+ - lib/perron/site/builder/feeds/template.rb
142
175
  - lib/perron/site/builder/page.rb
143
176
  - lib/perron/site/builder/paths.rb
144
177
  - lib/perron/site/builder/public_files.rb
178
+ - lib/perron/site/builder/route_resources.rb
145
179
  - lib/perron/site/builder/sitemap.rb
146
180
  - lib/perron/site/validate.rb
147
181
  - lib/perron/tasks/build.rake
148
182
  - lib/perron/tasks/clobber.rake
183
+ - lib/perron/tasks/install.rake
149
184
  - lib/perron/tasks/sync_sources.rake
150
185
  - lib/perron/tasks/validate.rake
151
186
  - lib/perron/version.rb
@@ -170,7 +205,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
170
205
  - !ruby/object:Gem::Version
171
206
  version: '0'
172
207
  requirements: []
173
- rubygems_version: 4.0.4
208
+ rubygems_version: 4.0.6
174
209
  specification_version: 4
175
210
  summary: Rails-based static site generator
176
211
  test_files: []
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FeedsHelper
4
- def feeds(options = {}) = Perron::Feeds.new.render(options)
5
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module MetaTagsHelper
4
- def meta_tags(options = {}) = Perron::Metatags.new(resource.metadata).render(options)
5
-
6
- private
7
-
8
- Resource = Data.define(:path, :collection, :metadata, :published_at)
9
-
10
- def resource
11
- return Resource.new(request.path, nil, @metadata, nil) if @metadata.present?
12
-
13
- @resource || Resource.new(request.path, nil, {}, nil)
14
- end
15
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Perron
4
- class InstallGenerator < Rails::Generators::Base
5
- source_root File.expand_path("templates", __dir__)
6
-
7
- desc "Install Perron in your Rails app"
8
-
9
- def copy_initializer
10
- template "initializer.rb.tt", "config/initializers/perron.rb"
11
- end
12
-
13
- def create_data_directory
14
- template "README.md.tt", "app/content/data/README.md"
15
- end
16
-
17
- def add_markdown_gems
18
- append_to_file "Gemfile", <<~RUBY
19
-
20
- # Perron supports Markdown rendering using one of the following gems.
21
- # Uncomment your preferred choice and run `bundle install`
22
- # gem "commonmarker"
23
- # gem "kramdown"
24
- # gem "redcarpet"
25
- RUBY
26
- end
27
-
28
- def gitignore_output_folder
29
- append_to_file ".gitignore", "/#{Perron.configuration.output}/\n"
30
- end
31
- end
32
- end
@@ -1,45 +0,0 @@
1
- # Data
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.
4
-
5
-
6
- ## Usage
7
-
8
- To use a data file, instantiate `Perron::Site.data` with the basename of the file and iterate over the result.
9
- ```erb
10
- <%% Perron::Site.data.features.each do |feature| %>
11
- <h4><%%= feature.name %></h4>
12
- <p><%%= feature.description %></p>
13
- <%% end %>
14
- ```
15
-
16
-
17
- ## File location and formats
18
-
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")`.
20
-
21
-
22
- ## Accessing data
23
-
24
- The wrapper object provides flexible, read-only access to each record's attributes. Both dot notation and hash-like key access are supported.
25
- ```ruby
26
- feature.name
27
- feature[:name]
28
- ```
29
-
30
-
31
- ## Rendering
32
-
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.
34
- ```erb
35
- <%%= render Perron::Site.data.features %>
36
- ```
37
-
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.
39
- ```erb
40
- <!-- app/views/content/features/_feature.html.erb -->
41
- <div class="feature">
42
- <h4><%%= feature.name %></h4>
43
- <p><%%= feature.description %></p>
44
- </div>
45
- ```
data/lib/perron/data.rb DELETED
@@ -1,180 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "csv"
4
-
5
- module Perron
6
- class Data < SimpleDelegator
7
- include Enumerable
8
-
9
- def initialize(identifier)
10
- @identifier = identifier
11
- @file_path = self.class.path_for!(identifier)
12
- @records = records
13
-
14
- super(records)
15
- end
16
-
17
- def each(&block) = @records.each(&block)
18
-
19
- def count = @records.count
20
-
21
- def first(n = nil)
22
- n ? @records.first(n) : @records.first
23
- end
24
-
25
- def last = @records.last
26
-
27
- def [](index) = @records[index]
28
-
29
- def size = @records.size
30
- alias_method :length, :size
31
-
32
- class << self
33
- def all
34
- parts = name.to_s.split("::").drop(2)
35
- identifier = parts.empty? ? name.demodulize.underscore : parts.map(&:underscore).join("/")
36
-
37
- new(identifier)
38
- end
39
-
40
- def find(id)
41
- all.find { it[:id] == id || it["id"] == id }
42
- end
43
-
44
- def count = all.size
45
-
46
- def first = all.first
47
-
48
- def second = all[1]
49
-
50
- def third = all[2]
51
-
52
- def fourth = all[3]
53
-
54
- def fifth = all[4]
55
-
56
- def forty_two = all[41]
57
-
58
- def last = all.last
59
-
60
- def take(n) = all.first(n)
61
-
62
- def path_for(identifier)
63
- path = Pathname.new(identifier)
64
-
65
- return path.to_s if path.file? && path.absolute?
66
-
67
- base_path = Rails.root.join("app", "content", "data")
68
-
69
- SUPPORTED_EXTENSIONS.lazy.map { base_path.join("#{identifier}#{it}") }.find(&:exist?)&.to_s
70
- end
71
-
72
- def path_for!(identifier)
73
- path_for(identifier).tap do |path|
74
- raise Errors::FileNotFoundError, "No data file found for `#{identifier}`" unless path
75
- end
76
- end
77
-
78
- def directory?(identifier) = Dir.exist?(Rails.root.join("app", "content", "data", identifier))
79
- end
80
-
81
- private
82
-
83
- PARSER_METHODS = {
84
- ".yml" => :parse_yaml, ".yaml" => :parse_yaml,
85
- ".json" => :parse_json, ".csv" => :parse_csv
86
- }.freeze
87
- SUPPORTED_EXTENSIONS = PARSER_METHODS.keys
88
-
89
- def records
90
- content = rendered_from(@file_path)
91
- data = parsed_from(content, @file_path)
92
-
93
- unless data.is_a?(Array)
94
- raise Errors::DataParseError, "Data in `#{@file_path}` must be an array of objects."
95
- end
96
-
97
- data.map { Item.new(it, identifier: @identifier) }
98
- end
99
-
100
- def rendered_from(path)
101
- raw_content = File.read(path)
102
-
103
- render_erb(raw_content)
104
- rescue NameError, ArgumentError, SyntaxError => error
105
- raise Errors::DataParseError, "Failed to render ERB in `#{path}`: (#{error.class}) #{error.message}"
106
- end
107
-
108
- def parsed_from(content, path)
109
- extension = File.extname(path)
110
- parser_method = PARSER_METHODS.fetch(extension) do
111
- raise Errors::UnsupportedDataFormatError, "Unsupported data format: #{extension}"
112
- end
113
-
114
- send(parser_method, content)
115
- rescue Psych::SyntaxError, JSON::ParserError, CSV::MalformedCSVError => error
116
- raise Errors::DataParseError, "Failed to parse data format in `#{path}`: (#{error.class}) #{error.message}"
117
- end
118
-
119
- def render_erb(content) = ERB.new(content).result(HelperContext.instance.get_binding)
120
-
121
- def parse_yaml(content)
122
- YAML.safe_load(content, permitted_classes: [Symbol, Time], aliases: true)
123
- end
124
-
125
- def parse_json(content)
126
- JSON.parse(content, symbolize_names: true)
127
- end
128
-
129
- def parse_csv(content)
130
- CSV.new(content, headers: true, header_converters: :symbol).to_a.map(&:to_h)
131
- end
132
-
133
- class HelperContext
134
- include Singleton
135
-
136
- def initialize
137
- self.class.include ActionView::Helpers::AssetUrlHelper
138
- self.class.include ActionView::Helpers::DateHelper
139
- self.class.include Rails.application.routes.url_helpers
140
- end
141
-
142
- def get_binding = binding
143
-
144
- def default_url_options = Perron.configuration.default_url_options || {}
145
- end
146
- private_constant :HelperContext
147
-
148
- class Item
149
- def initialize(attributes, identifier:)
150
- @attributes = attributes.transform_keys(&:to_sym)
151
- @identifier = identifier
152
- end
153
-
154
- def [](key) = @attributes[key.to_sym]
155
-
156
- def association_value(key) = self[key]
157
-
158
- def to_partial_path
159
- @to_partial_path ||= begin
160
- identifier = @identifier.to_s
161
- collection = File.extname(identifier).present? ? File.basename(identifier, ".*") : identifier
162
- element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.singularize(File.basename(collection)))
163
-
164
- File.join("content", collection, element)
165
- end
166
- end
167
-
168
- def method_missing(method_name, *arguments, &block)
169
- return super if !@attributes.key?(method_name) || arguments.any? || block
170
-
171
- @attributes[method_name]
172
- end
173
-
174
- def respond_to_missing?(method_name, include_private = false)
175
- @attributes.key?(method_name) || super
176
- end
177
- end
178
- private_constant :Item
179
- end
180
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rouge"
4
- require "perron/html_processor/base"
5
-
6
- module Perron
7
- class HtmlProcessor
8
- class SyntaxHighlight < HtmlProcessor::Base
9
- def process
10
- @html.css('pre > code[class*="language-"]').each do |code_block|
11
- language = code_block[:class][/(?<=language-)\S+/]
12
-
13
- next if language.blank?
14
-
15
- code_block.parent.replace(
16
- highlight(code_block.text, with: language)
17
- )
18
- end
19
- end
20
-
21
- private
22
-
23
- def highlight(code_block, with:)
24
- lexer = Rouge::Lexer.find(with) || Rouge::Lexers::PlainText.new
25
-
26
- Rouge::Formatters::HTMLPygments.new(::Rouge::Formatters::HTML.new).format(lexer.lex(code_block))
27
- end
28
- end
29
- end
30
- end