yart 0.0.1 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7a486f79b37a640e14193d98fdd17539bdb5415a11d678a7af8db53dff2132e4
4
- data.tar.gz: 2f299305146424573840e724c2daf55a2c60b36d2d0396865437e466efa33878
3
+ metadata.gz: 6dd8a4e37aedd9a60366cf53c6d3a270d098fb4739d2a4044b70c9515fe3f323
4
+ data.tar.gz: ad1b5c369574d17de2025fb1945bbb6a611d2ea88f239dfd08877af78a3e87d1
5
5
  SHA512:
6
- metadata.gz: 3601a9e16a699542998eecb169156a6a41832b8f018ff20683f9b1a1a20f9a5113702d90382d9432eabae5fb1213f38cfcb56eedc84d40534ec5031f4421f1c9
7
- data.tar.gz: d63dec7ebf153492407f7116f8f1da973f547e32efd20eab87b71520452b45585d868d3c3d335867345eb961f6302e060e83a74977a0e2d2c4230ab9ae9e879d
6
+ metadata.gz: b5eb0adbd6e5d46267db1c655248122c7e8028700ba315f16200a995d77ba4a815213a6a7b1374def5211fff61c82c3d930940cac5c907e94d4fa169cf4ed2b0
7
+ data.tar.gz: accd0937be8d188c1d7f5b46bd36739be711901d5eacdb667e7e891da4bc70230e00a313d314d3d46f64b5378f4670c5bef782aa2f3681c4601aedff606ab021
data/.gitignore CHANGED
@@ -6,3 +6,4 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ **/.byebug_history
data/Gemfile CHANGED
@@ -4,6 +4,9 @@ source "https://rubygems.org"
4
4
 
5
5
  ruby "~> 2.7"
6
6
 
7
- gem "minitest", "~> 5.0"
8
- gem "rake", "~> 13.0"
9
- gem "rubocop", "~> 1.7"
7
+ group :development do
8
+ gem "minitest", "~> 5.0"
9
+ gem "rake", "~> 13.0"
10
+ gem "rubocop", "~> 1.7"
11
+ gem "byebug", "~> 11.1"
12
+ end
data/Gemfile.lock CHANGED
@@ -2,6 +2,7 @@ GEM
2
2
  remote: https://rubygems.org/
3
3
  specs:
4
4
  ast (2.4.2)
5
+ byebug (11.1.3)
5
6
  minitest (5.14.4)
6
7
  parallel (1.20.1)
7
8
  parser (3.0.2.0)
@@ -25,9 +26,11 @@ GEM
25
26
  unicode-display_width (2.0.0)
26
27
 
27
28
  PLATFORMS
29
+ ruby
28
30
  x86_64-linux
29
31
 
30
32
  DEPENDENCIES
33
+ byebug (~> 11.1)
31
34
  minitest (~> 5.0)
32
35
  rake (~> 13.0)
33
36
  rubocop (~> 1.7)
data/README.md CHANGED
@@ -1,38 +1,44 @@
1
1
  # YART
2
2
 
3
- *Yet Another Ruby Templater* is yet another way to turn ruby code into HTML.
3
+ *Yet Another Ruby Templater* turns plain Ruby into HTML making it fun to write webpages.
4
4
 
5
- Can be used stand alone or embedded inside a higher level templater such as `erb` or `slim`. Is super good at building the changable bits of a webpage e.g. a form for posting to the server etc.
5
+ - YART provides an intuitive DSL that feels natural to use and removes the boiler plate from writing HTML
6
+ - YART has zero runtime dependencies and around 100 lines of code
7
+ - YART is fully unit tested
6
8
 
7
- ## Usage
9
+ ## Example Usage
10
+
11
+ > login.html
8
12
 
9
13
  ```ruby
10
- require 'yart'
14
+ require "yart"
11
15
 
12
16
  YART.parse do
13
- h1(id: :title) { 'YART' }
14
- div do
15
- h2 { 'Yet Another Ruby Templater' }
16
- p(class: [:content, :italic]) { 'Possibly the simplest way to turn sexy Ruby into boring HTML' }
17
- text { 'Ruby ruby ruby ruby aaaaahhhhhhawwwwwwwww' }
18
- end
17
+ form action: "/auth" do
18
+ input type: :email, placeholder: "Email Address", required: true, close: true
19
+ input type: :password, placeholder: "Password", required: true, close: true
20
+ button(type: :submit, id: :login) { "Login" }
21
+ end
19
22
  end
20
23
  ```
21
24
 
22
- Which produces and returns (from `YART.parse`):
25
+ Which renders:
23
26
 
24
27
  ```html
25
- <h1 id='title'>YART</h1>
26
- <div>
27
- <h2>Yet Another Ruby Templater</h2>
28
- <p class='content italic'>Possibly the simplest way to turn sexy Ruby into boring HTML</p>
29
- Ruby ruby ruby ruby aaaaahhhhhhawwwwwwwww
30
- </div>
28
+ <form action='/auth'>
29
+ <input type='email' placeholder='Email Address' required>
30
+ <input type='password' placeholder='Password' required>
31
+ <button type='submit' id='login'>Login</button>
32
+ </form>
31
33
  ```
32
34
 
35
+ Note that the above HTML snippet is *prettified* for demonstration. The actual generated HTML will be *minified*.
36
+
33
37
  ## Installation
34
38
 
35
- ### Ruby Gems
39
+ Requires Ruby `>= 2.7`
40
+
41
+ ### RubyGems
36
42
 
37
43
  $ gem install yart
38
44
 
@@ -40,6 +46,74 @@ Which produces and returns (from `YART.parse`):
40
46
 
41
47
  $ bundle add yart
42
48
 
49
+ ## API
50
+
51
+ The best way to fully demonstrate the YART API is with a more complex example:
52
+
53
+ ```ruby
54
+ require 'yart'
55
+
56
+ YART.parse do
57
+ element "!DOCTYPE", html: true, close: true # Or just call `doctype`
58
+ html lang: :en do
59
+ head do
60
+ title { "YART API" }
61
+ end
62
+ body do
63
+ h1 { "Use a block to return a String of innerText or more elements" }
64
+ div data_test_id: "String attribute values will be parsed as is" do
65
+ h2(data_x: :sub_heading) { "Symbol attribute keys/values will be kebab-cased" }
66
+ text { "Set the div's innerText, before and/or after its child elements" }
67
+ p(class: [:content, :italic_text], id: :paragraph) do
68
+ "You can pass an array of attribute values and they will be space separated"
69
+ end
70
+ end
71
+ footer # Render an empty <footer></footer> element
72
+ end
73
+ end
74
+ end
75
+ ```
76
+
77
+ Which renders, minifies and returns the following HTML5 from `YART.parse`:
78
+
79
+ ```html
80
+ <!DOCTYPE html>
81
+ <html lang='en'>
82
+ <head>
83
+ <title>YART API</title>
84
+ </head>
85
+ <body>
86
+ <h1>Use a block to return a String of innerText or more elements</h1>
87
+ <div data-test-id='String attribute values will be parsed as is'>
88
+ <h2 data-x='sub-heading'>Symbol attribute keys/values will be kebab-cased</h2>
89
+ Set the div's innerText, before and/or after its child elements
90
+ <p class='content italic-text' id='paragraph'>
91
+ You can pass an array of attribute values and they will be space separated
92
+ </p>
93
+ </div>
94
+ <footer></footer>
95
+ </body>
96
+ </html>
97
+ ```
98
+
99
+ Main points to note:
100
+
101
+ - Pass a block to `YART.parse` and it will render and return a HTML `String`.
102
+ - Create the HTML document hierarchy using element calls and blocks.
103
+ - Call the element as it's named in HTML, e.g. `h1`, `div`, `p` etc. This works as long as it's lowercase.
104
+ - Call `element` when you need to render the *raw* element name (case insensitive) e.g. `!DOCTYPE`.
105
+ - Pass the element's attributes as a `Hash` argument.
106
+ - Pass a block to return a `String` of `innerText` or more DSL calls (which will eventually return a `String`).
107
+ - An element doesn't require attributes or even a block. Where a block is absent, an empty element will be rendered.
108
+ - Use the `text` method to render the `innerText` of the element when it consists of *both* inner text *and* child elements.
109
+ - An attribute key or value of type `Symbol` will be parsed, converting `snake_case` to `kebab-case`.
110
+ - An attribute *value* of type `String` will be parsed as is (not modified in any way).
111
+ - An attribute *value* of `true` renders the attribute key without a value e.g. `input required: true` renders `<input required>`.
112
+ - Several attibute *values* can be rendered by passing an `Array` e.g. `p class: [:para, :italic]`. The values will be rendered space separated.
113
+ - Attribute *values* containing illegal characters (like quotes etc.) will be escaped in the rendered HTML.
114
+ - The attribute `close: true` is special and tells the parser to auto-close the element (because it's empty).
115
+ - Use the convenience methods `doctype`, `script` and `stylesheet` as needed.
116
+
43
117
  ## Development
44
118
 
45
119
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/bin/console CHANGED
@@ -2,14 +2,52 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "bundler/setup"
5
- require "yart"
5
+ require "irb"
6
+ require "byebug" # Call "byebug" anywhere in the code to debug.
6
7
 
7
- # You can add fixtures and/or initialization code here to make experimenting
8
- # with your gem easier. You can also use a different console, if you like.
8
+ # Define a method to facilitate the reloading of code changes.
9
+ def reload
10
+ original_verbose = $VERBOSE
11
+ $VERBOSE = nil # Suppress warning messages (from reloading CONSTANTS).
12
+ load "load.rb" # (Re)load all code changes.
13
+ $VERBOSE = original_verbose # Activate warning messages again globally.
14
+ true
15
+ end
9
16
 
10
- # (If you use this, don't forget to add pry to your Gemfile!)
11
- # require "pry"
12
- # Pry.start
17
+ # Load the most recent code into the session and include modules etc.
18
+ reload
19
+
20
+ # Load any fixture data into the session.
21
+ def login
22
+ proc do
23
+ form action: "/auth" do
24
+ input type: :email, placeholder: "Email Address", required: true, close: true
25
+ input type: :password, placeholder: "Password", required: true, close: true
26
+ button(type: :submit, id: :login) { "Login" }
27
+ end
28
+ end
29
+ end
30
+
31
+ def sample
32
+ proc do
33
+ doctype
34
+ html lang: :en do
35
+ head do
36
+ title { "YART API" }
37
+ end
38
+ body do
39
+ h1 { "Use a block to return a String of innerText or more elements" }
40
+ div data_test_id: "String attribute values will be parsed as is" do
41
+ h2(data_x: :sub_heading) { "Symbol attribute keys/values will be kebab-cased" }
42
+ text { "Set the div's innerText, before and/or after its child elements" }
43
+ p(class: [:content, :italic_text], id: :paragraph) do
44
+ "You can pass an array of attribute values and they will be space separated"
45
+ end
46
+ end
47
+ footer # Render an empty <footer></footer> element
48
+ end
49
+ end
50
+ end
51
+ end
13
52
 
14
- require "irb"
15
53
  IRB.start(__FILE__)
data/lib/yart.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "yart/version"
4
+ require_relative "yart/parser"
4
5
 
5
6
  module YART
6
- class Error < StandardError; end
7
- # Your code goes here...
7
+ extend Parser
8
8
  end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YART::Parser
4
+ CUSTOM_ATTRIBUTES = [:close]
5
+
6
+ # Parses a block of Ruby, rendering and returning a HTML String.
7
+ def parse(&block)
8
+ raise "Must pass a block to parse" unless block_given?
9
+
10
+ @@yart_buffer = []
11
+ instance_eval(&block)
12
+ @@yart_buffer.join
13
+ end
14
+
15
+ # Allows elements to be called and rendered via a DSL.
16
+ def method_missing(m, *args, &block)
17
+ attributes = args.fetch(0, {})
18
+
19
+ render(m, attributes, &block)
20
+ end
21
+
22
+ # Renders an element with the raw name (case insensitive).
23
+ def element(name, **attributes, &block)
24
+ render(name, attributes, &block)
25
+ end
26
+
27
+ # Renders a <!DOCTYPE html> element, for convenience.
28
+ def doctype
29
+ element("!DOCTYPE", html: true, close: true)
30
+ end
31
+
32
+ # Renders a JS <script src="..."> element, for convenience.
33
+ def script(src = nil, &block)
34
+ raise "Must pass a String param or a block returning a String" unless src || block_given?
35
+
36
+ src ||= block.call
37
+ element("script", src: src, close: true)
38
+ end
39
+
40
+ # Renders a CSS <link href="..."> element, for convenience.
41
+ def stylesheet(href = nil, &block)
42
+ raise "Must pass a String param or a block returning a String" unless href || block_given?
43
+
44
+ href ||= block.call
45
+ element("link", href: href, rel: :stylesheet, type: "text/css", close: true)
46
+ end
47
+
48
+ # Overrides Ruby's `p` method to render the element instead of printing.
49
+ def p(**attributes, &block)
50
+ render("p", attributes, &block)
51
+ end
52
+
53
+ # Sets the `innerText` of the element being rendered.
54
+ def text(str = nil, &block)
55
+ raise "Must pass a String param or a block returning a String" unless str || block_given?
56
+
57
+ str ||= block.call
58
+ buffer(str)
59
+ end
60
+
61
+ private
62
+
63
+ def buffer(str)
64
+ @@yart_buffer << str if str.is_a?(String)
65
+ end
66
+
67
+ def render(element, attributes, &block)
68
+ raise "Must pass attributes as a Hash" unless attributes.is_a?(Hash)
69
+
70
+ buffer(build_opening_tag(element, attributes))
71
+ buffer(instance_eval(&block)) if block_given?
72
+ buffer(build_closing_tag(element, attributes))
73
+ end
74
+
75
+ def build_opening_tag(element, attributes)
76
+ attributes_str = sanitise_attributes(attributes)
77
+ .reject { |k, v| CUSTOM_ATTRIBUTES.include?(k) }
78
+ .map { |k, v| v == true ? k.to_s : "#{k}='#{v}'" }
79
+ .join(" ")
80
+ separator = attributes_str.empty? ? "" : " "
81
+
82
+ "<#{element}#{separator}#{attributes_str}>"
83
+ end
84
+
85
+ def build_closing_tag(element, attributes)
86
+ attributes[:close] ? "" : "</#{element}>"
87
+ end
88
+
89
+ def sanitise_attributes(attributes)
90
+ attributes.map do |k, v|
91
+ k = kebab_case(k)
92
+ v = v.respond_to?(:map) ?
93
+ v.map { |v2| convert_attribute_value(v2) }.join(" ") :
94
+ convert_attribute_value(v)
95
+
96
+ [k, v]
97
+ end.to_h
98
+ end
99
+
100
+ def convert_attribute_value(value)
101
+ value = kebab_case(value)
102
+ value = replace_illegal_chars(value)
103
+
104
+ value
105
+ end
106
+
107
+ def kebab_case(s)
108
+ return s unless s.is_a?(Symbol)
109
+
110
+ s
111
+ .to_s
112
+ .gsub("_", "-")
113
+ .to_sym
114
+ end
115
+
116
+ def replace_illegal_chars(s)
117
+ return s unless s.is_a?(String)
118
+
119
+ s
120
+ .gsub('"', "&quot;")
121
+ .gsub("'", "&#39;")
122
+ .gsub("<", "&lt;")
123
+ .gsub(">", "&gt;")
124
+ end
125
+ end
data/lib/yart/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module YART
4
- VERSION = "0.0.1"
4
+ VERSION = "0.1.0"
5
5
  end
data/load.rb ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Development script which loads (all changes to) the code when called.
4
+
5
+ load 'lib/yart/version.rb'
6
+ load 'lib/yart/parser.rb'
7
+ load 'lib/yart.rb'
data/yart.gemspec CHANGED
@@ -8,9 +8,13 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["Michael Telford"]
9
9
  spec.email = ["michael.telford@live.com"]
10
10
 
11
- spec.summary = "Yet Another Ruby Templater is yet another way to turn ruby code into HTML"
11
+ spec.summary = "Yet Another Ruby Templater (YART) turns plain Ruby into HTML making it fun to write webpages."
12
12
  spec.description = <<~TEXT
13
- A Ruby to HTML templater. Can be used stand alone or embedded inside a higher level templater such as erb or slim. Is super good at building the changable bits of a webpage e.g. a form for posting to the server etc.
13
+ Yet Another Ruby Templater (YART) turns plain Ruby into HTML making it fun to write webpages.
14
+
15
+ - YART provides an intuitive DSL that feels natural to use and removes the boiler plate from writing HTML
16
+ - YART has zero runtime dependencies and ~120 LOC
17
+ - YART is fully unit tested
14
18
  TEXT
15
19
  spec.homepage = "https://github.com/michaeltelford/yart"
16
20
  spec.license = "MIT"
metadata CHANGED
@@ -1,20 +1,21 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yart
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Telford
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-27 00:00:00.000000000 Z
11
+ date: 2021-08-03 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: 'A Ruby to HTML templater. Can be used stand alone or embedded inside
14
- a higher level templater such as erb or slim. Is super good at building the changable
15
- bits of a webpage e.g. a form for posting to the server etc.
13
+ description: |
14
+ Yet Another Ruby Templater (YART) turns plain Ruby into HTML making it fun to write webpages.
16
15
 
17
- '
16
+ - YART provides an intuitive DSL that feels natural to use and removes the boiler plate from writing HTML
17
+ - YART has zero runtime dependencies and ~120 LOC
18
+ - YART is fully unit tested
18
19
  email:
19
20
  - michael.telford@live.com
20
21
  executables: []
@@ -34,7 +35,9 @@ files:
34
35
  - bin/console
35
36
  - bin/setup
36
37
  - lib/yart.rb
38
+ - lib/yart/parser.rb
37
39
  - lib/yart/version.rb
40
+ - load.rb
38
41
  - yart.gemspec
39
42
  homepage: https://github.com/michaeltelford/yart
40
43
  licenses:
@@ -61,5 +64,6 @@ requirements: []
61
64
  rubygems_version: 3.1.2
62
65
  signing_key:
63
66
  specification_version: 4
64
- summary: Yet Another Ruby Templater is yet another way to turn ruby code into HTML
67
+ summary: Yet Another Ruby Templater (YART) turns plain Ruby into HTML making it fun
68
+ to write webpages.
65
69
  test_files: []