archival 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b98cab63cfce4e643285b1da77a1536986cb6996bc06ebae39504ac0eff317c0
4
- data.tar.gz: be5bcec316ce9f5c240ed03c7186af5b4872465ec8b86f52e2db09aea3916985
3
+ metadata.gz: 2cb0c34388e5643a954509fca99931fc9b60d2705ba12733ea890eed817a549e
4
+ data.tar.gz: 29c8b6c12cd039be464211cd658b76cde06d4e20a8f2dad5b8f1921c0d40e76b
5
5
  SHA512:
6
- metadata.gz: 5eb2985aee73e4019e13fb833089ee33739657c0f4733f006de6e40c1be9af02e3f6539ded13aeb06b1bdf3a098b2dc65fe9b53b2c3f858845d6300a0c876921
7
- data.tar.gz: b0f5f0f435bf4635096a913b26360d599fa674c4663d4912345543556c055785002c7d99e9e6fb51d54a1a11255fa94a487fa4cedce15c36bcd18eb2e3750b21
6
+ metadata.gz: 1a6015cc2dafc8335acd969a1616b1842e8fb5afa9a6d966920d5399792a9fc774313e67b2c8467767f408f32eddc33660f7389954a515af6dcd386392ee74ba
7
+ data.tar.gz: 3b076507b17cde33ef678c8ced6a84efa4e69c927017dc411b6c4a9475eff5344cbeafd11396c5185fa8e3638854ae40e91ef9756a8c02303d2781839e7f886c
data/.bundle/config ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_BIN: "bin"
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,42 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ SuggestExtensions: false
4
+ Exclude:
5
+ - bin/bundle
6
+
7
+ Layout/LineLength:
8
+ Max: 80
9
+ Exclude:
10
+ - archival.gemspec
11
+ - bin/*
12
+ - spec/spec_helper.rb
13
+
14
+ Layout/TrailingWhitespace:
15
+ Exclude:
16
+ # This file has a lot of templates and includes
17
+ # intentional trailing whitespace.
18
+ - spec/tags/layout_spec.rb
19
+
20
+ Metrics/MethodLength:
21
+ Max: 35
22
+
23
+ Metrics/AbcSize:
24
+ Enabled: false
25
+
26
+ Metrics/BlockLength:
27
+ Max: 150
28
+
29
+ Metrics/ClassLength:
30
+ Max: 150
31
+
32
+ Lint/ImplicitStringConcatenation:
33
+ Exclude:
34
+ - spec/tags/layout_spec.rb
35
+
36
+ # A nice idea, but some code is self-documenting and cops aren't human.
37
+ Style/Documentation:
38
+ Enabled: false
39
+
40
+ # In Layout we use class vars as a global cache.
41
+ Style/ClassVars:
42
+ Enabled: false
@@ -0,0 +1,43 @@
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "type": "ruby-debug",
9
+ "request": "launch",
10
+ "name": "Ruby",
11
+ "program": "${file}",
12
+ "programArgs": [],
13
+ "useBundler": false
14
+ },
15
+ {
16
+ "type": "ruby-debug",
17
+ "request": "launch",
18
+ "name": "RSpec All",
19
+ "program": "rspec",
20
+ "programArgs": [
21
+ "-I",
22
+ "${workspaceFolder}",
23
+ ],
24
+ "useBundler": false
25
+ },
26
+ {
27
+ "type": "ruby-debug",
28
+ "request": "launch",
29
+ "name": "RSpec LocalFile",
30
+ "program": "rspec",
31
+ "programArgs": ["${relativeFile}"],
32
+ "useBundler": true
33
+ },
34
+ {
35
+ "type": "ruby-debug",
36
+ "request": "launch",
37
+ "name": "RSpec Selected Line",
38
+ "program": "rspec",
39
+ "programArgs": ["${relativeFile}:${lineNumber}"],
40
+ "useBundler": true
41
+ }
42
+ ]
43
+ }
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2021-10-28
4
+
5
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in archival.gemspec
6
+ gemspec
7
+
8
+ gem 'rake', '~> 13.0'
9
+ gem 'rspec', '~> 3.0'
10
+ gem 'rubocop', '~> 1.22', require: false
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <https://unlicense.org>
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # Archival
2
+
3
+ https://archival.dev
4
+
5
+ [![Rspec tests](https://github.com/jesseditson/archival/actions/workflows/rspec.yml/badge.svg)](https://github.com/jesseditson/archival/actions/workflows/rspec.yml)
6
+
7
+ ## Why?
8
+
9
+ Websites have become a bit homogenous, and basic web skills have become fairly accessible. This project aims to make it very easy to build ultra-durable websites that will last a very long time with little to no maintenance, and that don't rely on trendy build tools.
10
+
11
+ More musings about how this came about on my blog:
12
+
13
+ https://jesseditson.com/the-simplest-cms-part-1
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'archival'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ $ bundle install
26
+
27
+ Or install it yourself as:
28
+
29
+ $ gem install archival
30
+
31
+ ## Usage
32
+
33
+ First, install archival by running `gem install archival`.
34
+
35
+ Then, create a new website:
36
+
37
+ `archival create my-website`
38
+
39
+ This sets up some basics. To see your local website, run `archival run`.
40
+
41
+ When you push an archival website to github, it will automatically build itself to the `dist` folder. To see this locally, run `archival build`.
42
+
43
+ For more information and documentation, check out the docs at https://archival.dev
44
+
45
+ Archival uses as few domain specific languages as possible, but doesn't reinvent the wheel. Outside of web standards, here are the technologies used in Archival:
46
+
47
+ - https://shopify.github.io/liquid/basics/introduction/
48
+ - https://github.com/toml-lang/toml/wiki
49
+
50
+ ## Development
51
+
52
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
53
+
54
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
55
+
56
+ ## Contributing
57
+
58
+ Bug reports and pull requests are welcome on GitHub at https://github.com/jesseditson/archival.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+ require 'rubocop/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ RuboCop::RakeTask.new
10
+
11
+ task default: :spec
12
+ task lint: :rubocop
data/action.yml ADDED
@@ -0,0 +1,14 @@
1
+ name: 'Archival Build'
2
+ description: 'Packages a website built with Archival'
3
+ author: 'Jesse Ditson'
4
+ branding:
5
+ color: green
6
+ icon: box
7
+ runs:
8
+ using: 'composite'
9
+ steps:
10
+ - uses: ruby/setup-ruby@v1
11
+ with:
12
+ ruby-version: 3.0
13
+ bundler-cache: true
14
+ - run: bin/archival build
data/archival.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'archival'
5
+ s.version = '0.0.1'
6
+ s.summary = 'An incredibly simple CMS for durable websites'
7
+ s.description = 'https://jesseditson.com/the-simplest-cms-part-1'
8
+ s.authors = ['Jesse Ditson']
9
+ s.email = 'jesse.ditson@gmail.com'
10
+ s.homepage = 'https://archival.dev'
11
+ s.license = 'Unlicense'
12
+ s.required_ruby_version = '>= 2.5'
13
+
14
+ # Specify which files should be added to the gem when it is released.
15
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
16
+ s.files = Dir.chdir(File.expand_path(__dir__)) do
17
+ `git ls-files -z`.split("\x0").reject do |f|
18
+ (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
19
+ end
20
+ end
21
+ s.bindir = 'exe'
22
+ s.executables = 'archival'
23
+ s.require_paths = ['lib']
24
+
25
+ s.add_dependency 'liquid', '~> 5.1.0'
26
+ s.add_dependency 'listen', '~> 3.7.0'
27
+ s.add_dependency 'tomlrb', '~> 2.0.1'
28
+ end
data/bin/archival ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'archival' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path('bundle',
16
+ __dir__)
17
+
18
+ if File.file?(bundle_binstub)
19
+ if File.read(bundle_binstub,
20
+ 300) =~ /This file was generated by Bundler/
21
+ load(bundle_binstub)
22
+ else
23
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
24
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
25
+ end
26
+ end
27
+
28
+ require 'rubygems'
29
+ require 'bundler/setup'
30
+
31
+ load Gem.bin_path('archival', 'archival')
data/bin/bundle ADDED
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'bundle' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'rubygems'
12
+
13
+ m = Module.new do
14
+ module_function
15
+
16
+ def invoked_as_script?
17
+ File.expand_path($PROGRAM_NAME) == File.expand_path(__FILE__)
18
+ end
19
+
20
+ def env_var_version
21
+ ENV['BUNDLER_VERSION']
22
+ end
23
+
24
+ def cli_arg_version
25
+ return unless invoked_as_script? # don't want to hijack other binstubs
26
+ return unless 'update'.start_with?(ARGV.first || ' ') # must be running `bundle update`
27
+
28
+ bundler_version = nil
29
+ update_index = nil
30
+ ARGV.each_with_index do |a, i|
31
+ bundler_version = a if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
32
+ next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
33
+
34
+ bundler_version = Regexp.last_match(1)
35
+ update_index = i
36
+ end
37
+ bundler_version
38
+ end
39
+
40
+ def gemfile
41
+ gemfile = ENV['BUNDLE_GEMFILE']
42
+ return gemfile if gemfile && !gemfile.empty?
43
+
44
+ File.expand_path('../Gemfile', __dir__)
45
+ end
46
+
47
+ def lockfile
48
+ lockfile =
49
+ case File.basename(gemfile)
50
+ when 'gems.rb' then gemfile.sub(/\.rb$/, gemfile)
51
+ else "#{gemfile}.lock"
52
+ end
53
+ File.expand_path(lockfile)
54
+ end
55
+
56
+ def lockfile_version
57
+ return unless File.file?(lockfile)
58
+
59
+ lockfile_contents = File.read(lockfile)
60
+ return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
61
+
62
+ Regexp.last_match(1)
63
+ end
64
+
65
+ def bundler_requirement
66
+ @bundler_requirement ||=
67
+ env_var_version || cli_arg_version ||
68
+ bundler_requirement_for(lockfile_version)
69
+ end
70
+
71
+ def bundler_requirement_for(version)
72
+ return "#{Gem::Requirement.default}.a" unless version
73
+
74
+ bundler_gem_version = Gem::Version.new(version)
75
+
76
+ requirement = bundler_gem_version.approximate_recommendation
77
+
78
+ return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new('2.7.0')
79
+
80
+ requirement += '.a' if bundler_gem_version.prerelease?
81
+
82
+ requirement
83
+ end
84
+
85
+ def load_bundler!
86
+ ENV['BUNDLE_GEMFILE'] ||= gemfile
87
+
88
+ activate_bundler
89
+ end
90
+
91
+ def activate_bundler
92
+ gem_error = activation_error_handling do
93
+ gem 'bundler', bundler_requirement
94
+ end
95
+ return if gem_error.nil?
96
+
97
+ require_error = activation_error_handling do
98
+ require 'bundler/version'
99
+ end
100
+ if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
101
+ return
102
+ end
103
+
104
+ warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
105
+ exit 42
106
+ end
107
+
108
+ def activation_error_handling
109
+ yield
110
+ nil
111
+ rescue StandardError, LoadError => e
112
+ e
113
+ end
114
+ end
115
+
116
+ m.load_bundler!
117
+
118
+ load Gem.bin_path('bundler', 'bundle') if m.invoked_as_script?
data/bin/htmldiff ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'htmldiff' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path('bundle',
16
+ __dir__)
17
+
18
+ if File.file?(bundle_binstub)
19
+ if File.read(bundle_binstub,
20
+ 300) =~ /This file was generated by Bundler/
21
+ load(bundle_binstub)
22
+ else
23
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
24
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
25
+ end
26
+ end
27
+
28
+ require 'rubygems'
29
+ require 'bundler/setup'
30
+
31
+ load Gem.bin_path('diff-lcs', 'htmldiff')
data/bin/ldiff ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'ldiff' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path('bundle',
16
+ __dir__)
17
+
18
+ if File.file?(bundle_binstub)
19
+ if File.read(bundle_binstub,
20
+ 300) =~ /This file was generated by Bundler/
21
+ load(bundle_binstub)
22
+ else
23
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
24
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
25
+ end
26
+ end
27
+
28
+ require 'rubygems'
29
+ require 'bundler/setup'
30
+
31
+ load Gem.bin_path('diff-lcs', 'ldiff')
data/bin/listen ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'listen' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path('bundle',
16
+ __dir__)
17
+
18
+ if File.file?(bundle_binstub)
19
+ if File.read(bundle_binstub,
20
+ 300) =~ /This file was generated by Bundler/
21
+ load(bundle_binstub)
22
+ else
23
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
24
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
25
+ end
26
+ end
27
+
28
+ require 'rubygems'
29
+ require 'bundler/setup'
30
+
31
+ load Gem.bin_path('listen', 'listen')
data/bin/rake ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rake' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path('bundle',
16
+ __dir__)
17
+
18
+ if File.file?(bundle_binstub)
19
+ if File.read(bundle_binstub,
20
+ 300) =~ /This file was generated by Bundler/
21
+ load(bundle_binstub)
22
+ else
23
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
24
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
25
+ end
26
+ end
27
+
28
+ require 'rubygems'
29
+ require 'bundler/setup'
30
+
31
+ load Gem.bin_path('rake', 'rake')
data/bin/rspec ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rspec' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path('bundle',
16
+ __dir__)
17
+
18
+ if File.file?(bundle_binstub)
19
+ if File.read(bundle_binstub,
20
+ 300) =~ /This file was generated by Bundler/
21
+ load(bundle_binstub)
22
+ else
23
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
24
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
25
+ end
26
+ end
27
+
28
+ require 'rubygems'
29
+ require 'bundler/setup'
30
+
31
+ load Gem.bin_path('rspec-core', 'rspec')
data/bin/rubocop ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rubocop' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path('bundle',
16
+ __dir__)
17
+
18
+ if File.file?(bundle_binstub)
19
+ if File.read(bundle_binstub,
20
+ 300) =~ /This file was generated by Bundler/
21
+ load(bundle_binstub)
22
+ else
23
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
24
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
25
+ end
26
+ end
27
+
28
+ require 'rubygems'
29
+ require 'bundler/setup'
30
+
31
+ load Gem.bin_path('rubocop', 'rubocop')
data/bin/ruby-parse ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'ruby-parse' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path('bundle',
16
+ __dir__)
17
+
18
+ if File.file?(bundle_binstub)
19
+ if File.read(bundle_binstub,
20
+ 300) =~ /This file was generated by Bundler/
21
+ load(bundle_binstub)
22
+ else
23
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
24
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
25
+ end
26
+ end
27
+
28
+ require 'rubygems'
29
+ require 'bundler/setup'
30
+
31
+ load Gem.bin_path('parser', 'ruby-parse')
data/bin/ruby-rewrite ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'ruby-rewrite' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path('bundle',
16
+ __dir__)
17
+
18
+ if File.file?(bundle_binstub)
19
+ if File.read(bundle_binstub,
20
+ 300) =~ /This file was generated by Bundler/
21
+ load(bundle_binstub)
22
+ else
23
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
24
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
25
+ end
26
+ end
27
+
28
+ require 'rubygems'
29
+ require 'bundler/setup'
30
+
31
+ load Gem.bin_path('parser', 'ruby-rewrite')
data/bin/setup ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
data/exe/archival ADDED
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'archival'
5
+
6
+ VALID_COMMANDS = %w[
7
+ build
8
+ run
9
+ ].freeze
10
+
11
+ command = ARGV[0]
12
+
13
+ unless !command || VALID_COMMANDS.include?(command)
14
+ raise StandardError,
15
+ "Invalid command #{command}"
16
+ end
17
+
18
+ build_dir = Dir.pwd
19
+
20
+ case command
21
+ when 'build'
22
+ builder = Archival::Builder('root' => build_dir)
23
+ builder.write_all
24
+ when 'run'
25
+ Archival.listen(build_dir)
26
+ begin
27
+ sleep
28
+ rescue Interrupt
29
+ # Don't print a stack when a user interrupts, as this is the right way to
30
+ # stop the development server.
31
+ puts ''
32
+ end
33
+ else
34
+ # print help
35
+ puts 'archival [command]'
36
+ puts ''
37
+ puts 'Commands:'
38
+ puts ' build Builds the current directory as an archival website.'
39
+ puts ' run Runs the current directory in development mode, '
40
+ + 'recompiling when files change.'
41
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'liquid'
4
+ require 'tomlrb'
5
+ require 'tags/layout'
6
+
7
+ Liquid::Template.error_mode = :strict
8
+ Liquid::Template.register_tag('layout', Layout)
9
+
10
+ module Archival
11
+ class Builder
12
+ attr_reader :page_templates
13
+
14
+ def initialize(config, *_args)
15
+ @config = Config.new(config)
16
+ refresh_config
17
+ end
18
+
19
+ def refresh_config
20
+ @file_system = Liquid::LocalFileSystem.new(
21
+ @config.root, '%s.liquid'
22
+ )
23
+ @variables = {}
24
+ @object_types = {}
25
+ @page_templates = {}
26
+
27
+ Liquid::Template.file_system = @file_system
28
+
29
+ objects_definition_file = File.join(@config.root,
30
+ 'objects.toml')
31
+ if File.file? objects_definition_file
32
+ @object_types = read_toml(objects_definition_file)
33
+ end
34
+
35
+ update_pages
36
+ update_objects
37
+ end
38
+
39
+ def update_pages
40
+ do_update_pages(File.join(@config.root, @config.pages_dir))
41
+ end
42
+
43
+ def do_update_pages(dir, prefix = nil)
44
+ add_prefix = lambda { |entry|
45
+ prefix ? File.join(prefix, entry) : entry
46
+ }
47
+ Dir.foreach(dir) do |entry|
48
+ if File.directory? entry
49
+ unless [
50
+ '.', '..'
51
+ ].include?(entry)
52
+ update_pages(File.join(dir, entry),
53
+ add_prefix(entry))
54
+ end
55
+ elsif File.file? File.join(dir, entry)
56
+ if entry.end_with?('.liquid') && !(entry.start_with? '_')
57
+ page_name = File.basename(entry,
58
+ '.liquid')
59
+ template_file = File.join(
60
+ @config.pages_dir,
61
+ add_prefix.call(page_name)
62
+ )
63
+ content = @file_system.read_template_file(template_file)
64
+ @page_templates[add_prefix.call(page_name)] =
65
+ Liquid::Template.parse(content)
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ def update_objects
72
+ do_update_objects(File.join(@config.root,
73
+ @config.objects_dir))
74
+ end
75
+
76
+ def do_update_objects(dir)
77
+ objects = {}
78
+ @object_types.each do |name, _definition|
79
+ objects[name] = []
80
+ obj_dir = File.join(dir, name)
81
+ if File.directory? obj_dir
82
+ Dir.foreach(obj_dir) do |file|
83
+ if file.end_with? '.toml'
84
+ object = read_toml(File.join(
85
+ obj_dir, file
86
+ ))
87
+ object[:name] =
88
+ File.basename(file, '.toml')
89
+ objects[name].push object
90
+ end
91
+ end
92
+ end
93
+ objects[name] = objects[name].sort do |a, b|
94
+ (a['order'] || a[:name]).to_s <=> (b['order'] || b[:name]).to_s
95
+ end
96
+ end
97
+ @variables['objects'] = objects
98
+ end
99
+
100
+ def read_toml(file_path)
101
+ Tomlrb.load_file(file_path)
102
+ end
103
+
104
+ def set_var(name, value)
105
+ @variables[name] = value
106
+ end
107
+
108
+ def render(page)
109
+ template = @page_templates[page]
110
+ template.render(@variables)
111
+ end
112
+
113
+ def write_all
114
+ Dir.mkdir(@config.build_dir) unless File.exist? @config.build_dir
115
+ @page_templates.each_key do |template|
116
+ out_dir = File.join(@config.build_dir,
117
+ File.dirname(template))
118
+ Dir.mkdir(out_dir) unless File.exist? out_dir
119
+ out_path = File.join(@config.build_dir,
120
+ "#{template}.html")
121
+ File.open(out_path, 'w+') do |file|
122
+ file.write(render(template))
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archival
4
+ class Config
5
+ attr_reader :pages_dir, :objects_dir, :root, :build_dir
6
+
7
+ def initialize(config)
8
+ @pages_dir = config['pages'] || 'pages'
9
+ @objects_dir = config['objects'] || 'objects'
10
+ @root = config['root'] || Dir.pwd
11
+ @build_dir = config['build_dir'] || File.join(
12
+ @root, 'dist'
13
+ )
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'listen'
4
+ require 'pathname'
5
+
6
+ module Archival
7
+ def self.child?(parent, child)
8
+ path = Pathname.new(child)
9
+ return true if path.fnmatch?(File.join(parent, '**'))
10
+
11
+ false
12
+ end
13
+
14
+ def self.process_change?(file, builder)
15
+ if child?(File.join(@config.root, @config.pages_dir), file)
16
+ # a page was modified, rebuild the pages.
17
+ builder.update_pages
18
+ return true
19
+ elsif child?(File.join(@config.root, @config.objects_dir), file)
20
+ # an object was modified, rebuild the objects.
21
+ builder.update_objects
22
+ return true
23
+ end
24
+ false
25
+ end
26
+
27
+ def listen(config)
28
+ @config = Config.new(config)
29
+ builder = Builder.new(config)
30
+ builder.write_all
31
+ listener = Listen.to(@config.root) do |modified, added, removed|
32
+ needs_update = false
33
+ (modified + added + removed).each do |file|
34
+ needs_update = true if process_change?(file, builder)
35
+ end
36
+ builder.write_all if needs_update
37
+ end
38
+ listener.start
39
+ listener
40
+ end
41
+
42
+ module_function :listen
43
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rake'
4
+ require 'rake/tasklib'
5
+ require 'archival'
6
+
7
+ class RakeTasks
8
+ # Common tasks for archival.
9
+ #
10
+ # To include, just add
11
+ #
12
+ # require 'archival/rake_tasks'
13
+ #
14
+ # to your Rakefile.
15
+ include Rake::DSL if defined? Rake::DSL
16
+
17
+ class << self
18
+ # set when install'd.
19
+ attr_accessor :instance
20
+
21
+ def install_tasks
22
+ new.install
23
+ end
24
+ end
25
+
26
+ def install
27
+ build_dir = Dir.pwd
28
+
29
+ task 'build' do
30
+ builder = Archival::Builder.new('root' => build_dir)
31
+ builder.write_all
32
+ end
33
+
34
+ task 'run' do
35
+ Archival.listen(build_dir)
36
+ begin
37
+ sleep
38
+ rescue Interrupt
39
+ # Don't print a stack when a user interrupts, as this is the right way
40
+ # to stop the development server.
41
+ puts ''
42
+ end
43
+ end
44
+
45
+ RakeTasks.instance = self
46
+ end
47
+ end
48
+
49
+ RakeTasks.install_tasks
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archival
4
+ VERSION = '0.0.1'
5
+ end
data/lib/archival.rb CHANGED
@@ -1,3 +1,10 @@
1
+ # frozen_string_literal: true
1
2
 
2
- class Archival
3
- end
3
+ module Archival
4
+ # Main Archival module. See https://archival.dev for docs.
5
+ end
6
+
7
+ require 'archival/version'
8
+ require 'archival/config'
9
+ require 'archival/builder'
10
+ require 'archival/listen'
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'liquid'
4
+
5
+ class Layout < Liquid::Tag
6
+ # Adds a `layout` tag to liquid. Usage:
7
+ #
8
+ # {% layout [layout-name], "key" => "value" %}
9
+ #
10
+ # This will wrap the entire current template in the specified layout, with
11
+ # the arguments provided as local variables.
12
+
13
+ prepend Liquid::Tag::Disableable
14
+ @@layout_cache = {}
15
+
16
+ SYNTAX = /(#{Liquid::QuotedFragment}+)/o.freeze
17
+
18
+ attr_reader :layout_name_expr, :attributes
19
+
20
+ def self.reset_cache
21
+ @@layout_cache = {}
22
+ end
23
+
24
+ def initialize(tag_name, markup, tokens)
25
+ super
26
+
27
+ @page_content = []
28
+ raise 'Invalid layout syntax' unless markup =~ SYNTAX
29
+
30
+ layout_name = Regexp.last_match(1)
31
+ @layout_name_expr = parse_expression(layout_name)
32
+ @attributes = {}
33
+
34
+ markup.scan(Liquid::TagAttributes) do |key, value|
35
+ @attributes[key] = parse_expression(value)
36
+ end
37
+ end
38
+
39
+ def layout_path
40
+ base_path = Dir.pwd
41
+ layout_dir = 'layout'
42
+ layout_path = File.join(base_path, layout_dir)
43
+ raise "Layout dir #{layout_path} not found" unless File.exist? layout_path
44
+
45
+ layout_path
46
+ end
47
+
48
+ def load_layout(layout_name)
49
+ return @@layout_cache[layout_name] if @@layout_cache[layout_name]
50
+
51
+ found_layout = nil
52
+ Dir.entries(layout_path).each do |f|
53
+ next unless File.file? File.join(
54
+ layout_path, f
55
+ )
56
+
57
+ next unless File.basename(f, '.*') == layout_name
58
+ raise "More than one layout named #{layout_name} found." if found_layout
59
+
60
+ found_layout = File.join(layout_path, f)
61
+ end
62
+ raise "No layouts named #{layout_name} found." if found_layout.nil?
63
+
64
+ layout = File.read(found_layout)
65
+ @@layout_cache[layout_name] =
66
+ Liquid::Template.parse(layout)
67
+ @@layout_cache[layout_name]
68
+ end
69
+
70
+ def parse(tokens)
71
+ t = tokens.shift
72
+ while t
73
+ @page_content.push t
74
+ t = tokens.shift
75
+ end
76
+ end
77
+
78
+ def render_to_output_buffer(context, output)
79
+ layout_name = context.evaluate(@layout_name_expr)
80
+ raise 'Bad layout name argument' unless layout_name
81
+
82
+ layout = load_layout(layout_name)
83
+
84
+ old_template_name = context.template_name
85
+ old_partial = context.partial
86
+ begin
87
+ context.template_name = layout_name
88
+ context.partial = true
89
+ context.stack do
90
+ @attributes.each do |key, value|
91
+ context[key] = context.evaluate(value)
92
+ end
93
+ rendered_page = Liquid::Template.parse(@page_content.join)
94
+ .render(context)
95
+ context['page_content'] = rendered_page
96
+ layout.render_to_output_buffer(context,
97
+ output)
98
+ end
99
+ ensure
100
+ context.template_name = old_template_name
101
+ context.partial = old_partial
102
+ end
103
+
104
+ output
105
+ end
106
+ end
data/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "archival",
3
+ "version": "0.0.1",
4
+ "description": "An incredibly simple CMS for durable websites",
5
+ "bin": "build.rb",
6
+ "directories": {
7
+ "lib": "lib"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/jesseditson/archival.git"
12
+ },
13
+ "author": "Jesse Ditson <jesse.ditson@gmail.com>",
14
+ "license": "Unlicense",
15
+ "bugs": {
16
+ "url": "https://github.com/jesseditson/archival/issues"
17
+ },
18
+ "homepage": "https://github.com/jesseditson/archival#readme"
19
+ }
metadata CHANGED
@@ -1,23 +1,96 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: archival
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jesse Ditson
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2021-10-29 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2021-11-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: liquid
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.1.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 5.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: listen
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 3.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: 3.7.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: tomlrb
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 2.0.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 2.0.1
13
55
  description: https://jesseditson.com/the-simplest-cms-part-1
14
56
  email: jesse.ditson@gmail.com
15
- executables: []
57
+ executables:
58
+ - archival
16
59
  extensions: []
17
60
  extra_rdoc_files: []
18
61
  files:
62
+ - ".bundle/config"
63
+ - ".rspec"
64
+ - ".rubocop.yml"
65
+ - ".vscode/launch.json"
66
+ - CHANGELOG.md
67
+ - Gemfile
68
+ - LICENSE
69
+ - README.md
70
+ - Rakefile
71
+ - action.yml
72
+ - archival.gemspec
73
+ - bin/archival
74
+ - bin/bundle
75
+ - bin/htmldiff
76
+ - bin/ldiff
77
+ - bin/listen
78
+ - bin/rake
79
+ - bin/rspec
80
+ - bin/rubocop
81
+ - bin/ruby-parse
82
+ - bin/ruby-rewrite
83
+ - bin/setup
84
+ - exe/archival
19
85
  - lib/archival.rb
20
- homepage: https://rubygems.org/gems/archival
86
+ - lib/archival/builder.rb
87
+ - lib/archival/config.rb
88
+ - lib/archival/listen.rb
89
+ - lib/archival/rake_tasks.rb
90
+ - lib/archival/version.rb
91
+ - lib/tags/layout.rb
92
+ - package.json
93
+ homepage: https://archival.dev
21
94
  licenses:
22
95
  - Unlicense
23
96
  metadata: {}
@@ -29,7 +102,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
29
102
  requirements:
30
103
  - - ">="
31
104
  - !ruby/object:Gem::Version
32
- version: '0'
105
+ version: '2.5'
33
106
  required_rubygems_version: !ruby/object:Gem::Requirement
34
107
  requirements:
35
108
  - - ">="