triplet 0.1.2 → 0.2.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: b40b0b70887646a31162a22cabddccae123dbccda5d43dc80fd7242b5aa94f81
4
- data.tar.gz: 48bfda56958ed0fe61cb24706217b7f64488cd5154ef6f35385cb090abc956f0
3
+ metadata.gz: 6ec92ece8a32167845522f68fc13eb3626fc8050a50c2d9d2a3ec584a6484352
4
+ data.tar.gz: 776de546e4d65f5e86a918a6b6df82e0d6943865d45bfa141c68fa9392a5b065
5
5
  SHA512:
6
- metadata.gz: a41c7887916837e1f588fd5ebb224d5de2995abba38f2724d1dbb02aa7c9bea51d59b340851d98cc0fe362aa805f2f226870e745af06bf3224c6bc83fd69dfbe
7
- data.tar.gz: a6dd49020e45e0feeb3e0ee616f3c04832956c4a6c0c7d133b8435874092f2d7c7a15861f9b815f5c2025811af62733060ffae0a22acd83ff11e2b3e3a36412c
6
+ metadata.gz: c1136f57bb9c8f01e6ea6bae45fae3d86ec41257f748ffdcc379d8872cf67c516013eac3d06b2184f2d0ba8ff15beb09e3cffcb9b568cf6de2d65380e2fe2ccf
7
+ data.tar.gz: 42e305e5979eee1de486473a7bcc38d0172e1f7da5df5fed4ab0960562ccca9a38b24c5fe245322cc76ae10ec2556dcb9994a0a1e1941e3021685b2a6ef1e236
@@ -0,0 +1,23 @@
1
+ name: Ruby
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ ruby: [ '2.5', '2.6', '2.7' ]
15
+ steps:
16
+ - uses: actions/checkout@v2
17
+ - uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: ${{ matrix.ruby }}
20
+ - name: Install dependencies
21
+ run: bundle install
22
+ - name: Run tests
23
+ run: bundle exec rake
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- triplet (0.1.2)
4
+ triplet (0.2.0)
5
5
  actionview (>= 5.0.0, < 7.0)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -3,6 +3,14 @@
3
3
  A simple Ruby DSL for defining templates. (Maybe) useful for defining single file [view
4
4
  components](https://github.com/github/view_component).
5
5
 
6
+ Features:
7
+
8
+ * Easy to use "AST" for defining HTML tags. `[:a, { href: "/" }, "Home"]`
9
+ * DSL methods to make defining triplets easier. `a(href: "/") { "Home" }`
10
+ * Supports Rails helper methods. e.g. `form_for`, `text_field_tag`, `link_to`,
11
+ etc.
12
+ * View Component support via `include Triplet::ViewComponent`
13
+
6
14
  ## Installation
7
15
 
8
16
  Add this line to your application's Gemfile:
@@ -18,22 +26,18 @@ And then execute: `bundle install` in your shell.
18
26
  ```ruby
19
27
  nav_items = { "home": "/", "Sign Up": "/sign-up" }
20
28
 
21
- Triplet.template do
22
- nav class: "max-w-3xl mx-auto flex" do
23
- h1(class: "font-3xl") { "My App" }
24
-
25
- ul class: "" do
26
- nav_items.each do |name, link|
27
- li class: "bold font-xl" do
28
- a href: link.html_safe { name }
29
- end
29
+ Triplet.template {[
30
+ nav(class: "max-w-3xl mx-auto flex") {[
31
+ h1(class: "font-3xl") { "My App" },
32
+ ul(class: "") {[
33
+ nav_items.map do |name, link|
34
+ li(class: "bold font-xl") {[ a(href: link.html_safe) { name } ]}
30
35
  end
31
- end
32
- end
33
-
34
- text "Hello"
35
- span(class: "bold") { "world" }
36
- end
36
+ ]}
37
+ ]},
38
+ "Hello",
39
+ span(class: "bold") { "world" },
40
+ ]}
37
41
  ```
38
42
 
39
43
  Will output the equivalent HTML:
@@ -42,26 +46,25 @@ Will output the equivalent HTML:
42
46
  <nav class="max-w-3xl mx-auto flex">
43
47
  <h1 class="font-3xl">My App</h1>
44
48
  <ul class="">
45
- <li class="bold font-xl"><a href="/"></a></li>
46
- <li class="bold font-xl"><a href="/sign-up"></a></li>
49
+ <li class="bold font-xl"><a href="/">home</a></li>
50
+ <li class="bold font-xl"><a href="/sign-up">Sign Up</a></li>
47
51
  </ul>
48
52
  </nav>
49
53
  Hello<span class="bold">world</span>
50
54
  ```
51
55
 
52
- If you need a custom tag, you can use the `tag` helper method:
56
+ The tag methods (e.g. `nav`, `h1`, `p`) are helpers that turn Ruby code into
57
+ triples, or 3 element arrays.
53
58
 
54
- ```ruby
55
- tag("my-tag", "custom-attribute" => "value") { "body content" }
56
- # <my-tag custom-attribute="value">body content</my-tag>
57
- ```
59
+ e.g. `p(class: "font-xl") { "hello world!" }` becomes `[:p, { class: "font-xl" }, "hello world!"]`
58
60
 
59
- To output strings with no wrapping tag, use the `text` helper:
61
+ The two formats can be used interchangeably in templates.
62
+
63
+ If you need a custom tag, you can return a triplet directly:
60
64
 
61
65
  ```ruby
62
- text "hello "
63
- b { "world" }
64
- # hello <b>world</b>
66
+ [:"my-tag", { "custom-attribute" => "value" }, ["body content"]]
67
+ # <my-tag custom-attribute="value">body content</my-tag>
65
68
  ```
66
69
 
67
70
  ### View Component Support
@@ -70,14 +73,15 @@ To use in view components, include the `Triplet::ViewComponent` module and
70
73
  define a `call` method. The module will handle the rest.
71
74
 
72
75
  ```ruby
73
- class NavComponent < ::ViewComponent::Base
76
+ class NavComponent < ViewComponent::Base
74
77
  include Triplet::ViewComponent
75
78
 
76
- def call
77
- h1 { "hello world" }
78
-
79
- render NavItemComponent.new(title: "Home", path: "/")
80
- render NavItemComponent.new(title: "Pricing", path: "/pricing")
79
+ def template
80
+ [
81
+ h1 { "hello world" },
82
+ render NavItemComponent.new(title: "Home", path: "/"),
83
+ render NavItemComponent.new(title: "Pricing", path: "/pricing")
84
+ ]
81
85
  end
82
86
  end
83
87
  ```
@@ -3,8 +3,8 @@
3
3
  require "action_view" # Necessary for output buffer
4
4
 
5
5
  require "triplet/version"
6
- require "triplet/template"
7
6
  require "triplet/dsl"
7
+ require "triplet/template"
8
8
 
9
9
  module Triplet
10
10
  class Error < StandardError; end
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Triplet
4
4
  module DSL
5
+ include ActionView::Helpers::CaptureHelper
6
+ include ActionView::Helpers::TagHelper
7
+
5
8
  TAGS = [
6
9
  :a, :abbr, :address, :area, :article, :aside, :audio,
7
10
  :b, :base, :bdi, :bdo, :blockquote, :body, :br, :button,
@@ -30,61 +33,51 @@ module Triplet
30
33
  # TODO handle VOID_TAGS specially
31
34
  TAGS.each do |tag|
32
35
  define_method tag do |attrs = {}, &block|
33
- tag(tag, attrs, &block)
36
+ [
37
+ tag,
38
+ attrs,
39
+ block&.call,
40
+ ]
34
41
  end
35
42
  end
36
43
 
37
- def text(text)
38
- @output_buffer << text
39
- end
40
-
41
- def tag(tag, attrs = {}, &block)
42
- @output_buffer.safe_concat "<#{tag}"
43
- @output_buffer.safe_concat " " unless attrs.empty?
44
- _write_attributes(attrs)
45
- @output_buffer.safe_concat ">"
46
-
47
- if block
48
- value = nil
49
- result = capture do
50
- value = block.call
51
- end
44
+ def render_triplet(triplet)
45
+ if triplet.is_a?(String)
46
+ triplet
47
+ elsif triplet.is_a?(Array)
48
+ # If the array size is 3 and the first object is a
49
+ # symbol, it's likely a renderable triplet
50
+ if triplet.length == 3 && triplet[0].is_a?(Symbol)
51
+ tag, attrs, children = triplet
52
52
 
53
- # Supports returning a string directlycfrom blocks
54
- if result.length == 0 && value
55
- @output_buffer << value
53
+ content_tag(tag, attrs) do
54
+ if children.is_a?(Array)
55
+ safe_join(children.map { |c| render_triplet(c) }, "")
56
+ else
57
+ render_triplet(children)
58
+ end
59
+ end
56
60
  else
57
- @output_buffer << result
61
+ safe_join(triplet.map { |c| render_triplet(c) }, "")
58
62
  end
63
+ else
64
+ triplet.to_s
59
65
  end
60
-
61
- @output_buffer.safe_concat "</#{tag}>"
62
66
  end
63
67
 
64
68
  private
65
69
 
66
- def _write_attributes(attrs)
67
- attrs.each_with_index do |(k,v), i|
68
- @output_buffer << k.to_s
69
- @output_buffer.safe_concat '="'
70
- @output_buffer << v.to_s
71
- @output_buffer.safe_concat '"'
72
- @output_buffer.safe_concat ' ' if i != attrs.length - 1
73
- end
74
- end
70
+ attr_accessor :output_buffer
75
71
 
76
- def capture
77
- original_output_buffer = @output_buffer
78
-
79
- begin
80
- @output_buffer = ActionView::OutputBuffer.new
81
- yield
82
- @output_buffer
83
- ensure
84
- @output_buffer = original_output_buffer
72
+ # Override capture to support triplets
73
+ def capture(*args)
74
+ value = nil
75
+ buffer = with_output_buffer { value = yield(*args) }
76
+ if (string = buffer.presence || value) && string.is_a?(String)
77
+ ERB::Util.html_escape string
78
+ elsif value.is_a?(Array) # This is the only change, adds triplet support
79
+ render_triplet(value)
85
80
  end
86
81
  end
87
82
  end
88
83
  end
89
-
90
- Triplet::Template.include(Triplet::DSL)
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ require "view_component"
4
+
5
+ module Triplet
6
+ module RailsCompatibility
7
+ VALID_SUFFIXES = ["_field", "_button", "text_area"].freeze
8
+ VALID_METHODS = [
9
+ "form_for",
10
+ "form_with",
11
+ "label",
12
+ "fields_for",
13
+ "fields",
14
+ ].freeze
15
+ include ActionView::Helpers::FormTagHelper
16
+ include ActionView::Helpers::FormHelper
17
+
18
+ # Override helpers to modify @output_buffer directly
19
+ (
20
+ ActionView::Helpers::FormTagHelper.public_instance_methods +
21
+ ActionView::Helpers::FormHelper.public_instance_methods
22
+ ).each do |method|
23
+ alias_method :"original_#{method}", method
24
+ define_method method do |*args, **kwargs, &block|
25
+ puts "calling #{method}"
26
+ result = public_send(:"original_#{method}", *args, **kwargs, &block)
27
+
28
+ if result.class < String
29
+ @output_buffer << result
30
+ end
31
+
32
+ nil # Necessary to prevent double renders
33
+ end
34
+ end
35
+ end
36
+ end
@@ -2,10 +2,12 @@
2
2
 
3
3
  module Triplet
4
4
  class Template
5
+ include Triplet::DSL
6
+
5
7
  def initialize(output_buffer = ActionView::OutputBuffer.new, &block)
6
8
  @output_buffer = output_buffer
7
9
 
8
- instance_eval(&block)
10
+ @output_buffer << render_triplet(instance_eval(&block))
9
11
  end
10
12
 
11
13
  def to_s
@@ -1,3 +1,3 @@
1
1
  module Triplet
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -5,10 +5,12 @@ require "view_component"
5
5
  module Triplet
6
6
  module ViewComponent
7
7
  include Triplet::DSL
8
+ alias_method :template_tag, :template
8
9
 
9
- def render_in(view_context, &block)
10
- @output_buffer ||= ActionView::OutputBuffer.new
11
- super(view_context, &block)
10
+ def self.included(klass)
11
+ klass.define_method(:call) do
12
+ render_triplet(template)
13
+ end
12
14
  end
13
15
  end
14
16
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: triplet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Blake Williams
@@ -107,6 +107,7 @@ executables: []
107
107
  extensions: []
108
108
  extra_rdoc_files: []
109
109
  files:
110
+ - ".github/workflows/ruby.yml"
110
111
  - ".gitignore"
111
112
  - ".travis.yml"
112
113
  - Gemfile
@@ -118,6 +119,7 @@ files:
118
119
  - bin/setup
119
120
  - lib/triplet.rb
120
121
  - lib/triplet/dsl.rb
122
+ - lib/triplet/rails_compatibility.rb
121
123
  - lib/triplet/template.rb
122
124
  - lib/triplet/version.rb
123
125
  - lib/triplet/view_component.rb