yart 0.0.1 → 0.1.0

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: 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: []