Compare commits

...

9 Commits

Author SHA1 Message Date
maddiebaka 4d0f9802fc Full parser multiline support 🎉 2023-08-03 17:31:14 -04:00
maddiebaka 9dcb59d8d4 Verbatim and list multi-line parser implementation 2023-08-03 17:31:14 -04:00
maddiebaka eb8325f20a Switch to case-implementation of parser 2023-08-03 17:31:14 -04:00
maddiebaka 1e2dba2630 Remove old implementation of strip_markers 2023-08-03 17:31:14 -04:00
maddiebaka 26cbb6d345 Htmlizer implementation 2023-08-03 17:31:14 -04:00
maddiebaka 9c99732c24 Fix strip_markers step 2023-08-03 17:31:14 -04:00
maddiebaka 72e841cfcc Verbatim lines collapsing on parse 2023-08-03 17:31:14 -04:00
maddiebaka b150a808ab Basic parser implementation 2023-08-03 17:31:14 -04:00
maddiebaka 7e0640dc1c Initial commit - Rebase of local and remote branches 2023-08-03 17:31:02 -04:00
18 changed files with 510 additions and 2 deletions

12
.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
/.bundle/
/.yardoc
/_yardoc/
/coverage/
/doc/
/pkg/
/spec/reports/
/tmp/
# rspec failure tracking
.rspec_status
pub_gemini

3
.rspec Normal file
View File

@ -0,0 +1,3 @@
--format documentation
--color
--require spec_helper

3
.standard.yml Normal file
View File

@ -0,0 +1,3 @@
# For available configuration options, see:
# https://github.com/testdouble/standard
ruby_version: 2.6

13
Gemfile Normal file
View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
source "https://rubygems.org"
# Specify your gem's dependencies in skeksis.gemspec
gemspec
gem "rake", "~> 13.0"
gem "rackup"
gem "rspec", "~> 3.0"
gem "standard", "~> 1.3"

82
Gemfile.lock Normal file
View File

@ -0,0 +1,82 @@
PATH
remote: .
specs:
skeksis (0.1.0)
GEM
remote: https://rubygems.org/
specs:
ast (2.4.2)
diff-lcs (1.5.0)
json (2.6.3)
language_server-protocol (3.17.0.3)
lint_roller (1.1.0)
parallel (1.23.0)
parser (3.2.2.3)
ast (~> 2.4.1)
racc
racc (1.7.1)
rack (3.0.8)
rackup (2.1.0)
rack (>= 3)
webrick (~> 1.8)
rainbow (3.1.1)
rake (13.0.6)
regexp_parser (2.8.1)
rexml (3.2.6)
rspec (3.12.0)
rspec-core (~> 3.12.0)
rspec-expectations (~> 3.12.0)
rspec-mocks (~> 3.12.0)
rspec-core (3.12.2)
rspec-support (~> 3.12.0)
rspec-expectations (3.12.3)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-mocks (3.12.6)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-support (3.12.1)
rubocop (1.52.1)
json (~> 2.3)
parallel (~> 1.10)
parser (>= 3.2.2.3)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.28.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.29.0)
parser (>= 3.2.1.0)
rubocop-performance (1.18.0)
rubocop (>= 1.7.0, < 2.0)
rubocop-ast (>= 0.4.0)
ruby-progressbar (1.13.0)
standard (1.30.1)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.0)
rubocop (~> 1.52.0)
standard-custom (~> 1.0.0)
standard-performance (~> 1.1.0)
standard-custom (1.0.2)
lint_roller (~> 1.0)
rubocop (~> 1.50)
standard-performance (1.1.2)
lint_roller (~> 1.1)
rubocop-performance (~> 1.18.0)
unicode-display_width (2.4.2)
webrick (1.8.1)
PLATFORMS
arm64-darwin-22
DEPENDENCIES
rackup
rake (~> 13.0)
rspec (~> 3.0)
skeksis!
standard (~> 1.3)
BUNDLED WITH
2.4.15

View File

@ -1,3 +1,31 @@
# skeksis
# Skeksis
A gemini to https bridge in Ruby. Written in rack.
TODO: Delete this and the text below, and describe your gem
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/skeksis`. To experiment with that code, run `bin/console` for an interactive prompt.
## Installation
TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
Install the gem and add to the application's Gemfile by executing:
$ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
If bundler is not being used to manage dependencies, install the gem by executing:
$ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
## Usage
TODO: Write usage instructions here
## Development
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
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).
## Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/maddiebaka/skeksis.

10
Rakefile Normal file
View File

@ -0,0 +1,10 @@
# frozen_string_literal: true
require "bundler/gem_tasks"
require "rspec/core/rake_task"
RSpec::Core::RakeTask.new(:spec)
require "standard/rake"
task default: %i[spec standard]

11
bin/console Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require "bundler/setup"
require "skeksis"
# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.
require "irb"
IRB.start(__FILE__)

8
bin/setup Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx
bundle install
# Do any other automated setup that you need to do here

28
config.ru Normal file
View File

@ -0,0 +1,28 @@
require 'skeksis'
SERVE_DIR="/Users/madeline/Code/gemini-bridge-rack/gemini"
class SkeksisApp
def call(env)
status = 200
headers = { "content-type" => "text/html" }
#headers = {}
body = resolve_path(SERVE_DIR + env['PATH_INFO'])
[status, headers, body]
end
def resolve_path(path)
if Dir.exist?(path)
return Dir.each_child(path).map {|i| "#{i}\n"}
elsif File.exist?(path)
file = File.open(path, 'r')
data = file.readlines
[Skeksis.htmlize(data)]
else # path is invalid
return nil
end
end
end
run SkeksisApp.new

16
lib/skeksis.rb Normal file
View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
require_relative "skeksis/version"
require_relative "skeksis/parser"
require_relative "skeksis/htmlize"
module Skeksis
class Error < StandardError; end
# Your code goes here...
extend self
def htmlize(data)
#puts Skeksis::Parser.parse(data).htmlize
Skeksis::Parser.parse(data).htmlize
end
end

60
lib/skeksis/htmlize.rb Normal file
View File

@ -0,0 +1,60 @@
module Skeksis
class IR
Header = <<~HTML
<html>
<head>
<title>Gembridge</title>
</head>
<body>
HTML
Footer = <<~HTML
</body>
</html>
HTML
def htmlize
build_html_doc
end
private
def build_html_doc
content = self.parse_ir.join("\n")
Header + "#{content}\n" + Footer
end
def parse_ir
html = self.map do |entry|
content = lambda { |entry|
unless entry[:content].nil? then return entry[:content][0] end
}
text = content.call(entry)
case entry[:type]
when :blank
"<br/>"
when :header
level = entry[:level]
"<h#{level}>#{text}</h#{level}>"
when :list
# TODO: Does not handle lists properly, only one <ul> tag per group of lists needs to be
# created instead
"<ul><li>#{text}</li></ul>"
when :quote
"<pre>#{text}</pre>"
when :uri
uri = entry[:uri]
text = entry[:text]
"<a href=\"#{uri}\">#{text}</a>"
when :verbatim
"<pre>" + entry[:content].join("\n") + "</pre>"
when :text
"<p>#{text}</p>"
end
end
html
end
end
end

160
lib/skeksis/parser.rb Normal file
View File

@ -0,0 +1,160 @@
# Code adapted from MIT-licensed gemini-rb project
# parser.rb hosted at
# https://github.com/genenetwork/gemini-rb/blob/main/lib/gemini-rb/parser.rb
#
# Internal Representation types
# :blank
# :header
# :list
# :quote
# :uri
# :verbatim
# :text
#
module Skeksis
class IR < Array
def strip_markers!
self.map! do |line|
type = line[:type]
content = line[:content]
text = content[0]
case type
when :blank
#{ type: type, content: nil }
{ type: type }
when :header
m = /^(#+)(\s*)(.*)/.match(text)
level = m[1].count("#")
{ type: type, level: level, content: [m[3]] }
when :list
{ type: type, content: content.map { |t| t.sub(/^\*\s*/, "") } }
when :quote
{ type: type, content: content.map { |t| t.sub(/^\>\s?/, "") } }
when :uri
a = text.sub(/^=>\s*/, "").split(" ", 2)
link = a[0]
text = a[1]
{ type: type, link: link, text: text }
when :verbatim
# TODO: Match with syntax highlighting, maybe
content.map! do |line|
m = /^```(.*)/.match(line)
unless m.nil?
nil
else
line
end
end.compact!
{ type: type, content: content }
else
{ type: type, content: content }
end
end.compact!
end
end
module Parser
extend self
def parse(input)
puts("##### PARSING STARTED #####")
list = IR.new
data = input.map(&:chomp)
in_verbatim_block = false
in_multiline_block = false
in_block = nil
content = []
data.each do |line|
type = get_type(line)
case type
when :list, :quote
if not in_verbatim_block
in_multiline_block = true
in_block = type
end
content.push(line)
when :verbatim
if in_verbatim_block == false
in_verbatim_block = true
content.push(line)
elsif in_verbatim_block == true
in_verbatim_block = false
content.push(line)
list.push({ type: :verbatim, content: content })
content = []
next
end
else
if in_multiline_block == true
#puts("in multiline block")
list.push({ type: in_block, content: content })
in_multiline_block = false
content = []
end
if in_verbatim_block == true
content.push(line)
end
end
#if type == :verbatim and in_verbatim_block == false
# in_verbatim_block = true
# content.push(line)
#elsif type != :verbatim and in_verbatim_block == true
# content.push(line)
#elsif type == :verbatim and in_verbatim_block == true
# in_verbatim_block = false
# content.push(line)
# list.push({ type: :verbatim, content: content })
# content = []
# next
#end
if in_verbatim_block == false and in_multiline_block == false
#puts("catch-all push")
list.push({ type: type, content: [line] })
end
end
list.strip_markers!
puts list
#puts strip_markers(list)
puts("##### PARSING FINISHED #####")
list
end
private
def collapse_verbatim_blocks(gemtext)
end
def get_type(l)
case l
when ""
:blank
when /^#/
:header
when /^\*/
:list
when /^\>/
:quote
when /^\=>/
:uri
when /^```/
:verbatim
else
:text
end
end
end
end

5
lib/skeksis/version.rb Normal file
View File

@ -0,0 +1,5 @@
# frozen_string_literal: true
module Skeksis
VERSION = "0.1.0"
end

4
sig/skeksis.rbs Normal file
View File

@ -0,0 +1,4 @@
module Skeksis
VERSION: String
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
end

39
skeksis.gemspec Normal file
View File

@ -0,0 +1,39 @@
# frozen_string_literal: true
require_relative "lib/skeksis/version"
Gem::Specification.new do |spec|
spec.name = "skeksis"
spec.version = Skeksis::VERSION
spec.authors = ["maddiebaka"]
spec.email = ["madeline@cray.lgbt"]
spec.summary = "An http->gemini bridge in ruby"
#spec.description = "TODO: Write a longer description or delete this line."
spec.homepage = "https://maddie.info"
spec.required_ruby_version = ">= 2.6.0"
#spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
spec.metadata["homepage_uri"] = spec.homepage
#spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
#spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(__dir__) do
`git ls-files -z`.split("\x0").reject do |f|
(File.expand_path(f) == __FILE__) ||
f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
end
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
# Uncomment to register a new dependency of your gem
# spec.add_dependency "example-gem", "~> 1.0"
# For more information and examples about making a new gem, check out our
# guide at: https://bundler.io/guides/creating_gem.html
end

11
spec/skeksis_spec.rb Normal file
View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
RSpec.describe Skeksis do
it "has a version number" do
expect(Skeksis::VERSION).not_to be nil
end
it "does something useful" do
expect(false).to eq(true)
end
end

15
spec/spec_helper.rb Normal file
View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
require "skeksis"
RSpec.configure do |config|
# Enable flags like --only-failures and --next-failure
config.example_status_persistence_file_path = ".rspec_status"
# Disable RSpec exposing methods globally on `Module` and `main`
config.disable_monkey_patching!
config.expect_with :rspec do |c|
c.syntax = :expect
end
end