rblade 0.4.0 → 0.5.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: 6a3fbdc85ee9754a8b3c184a389407a0df5e145f0f0613069386cc5ca488ac2c
4
- data.tar.gz: 0f1c60eb458e89dfe8f57ce8e225b2a1ec643bf9a5f5c393d62cb96a4bf85970
3
+ metadata.gz: d795f1e81eb6dd60c3c581ccb22de43921bfab0997eb45daf6309298fb83fc5d
4
+ data.tar.gz: 2189078e98ad7ede598bc77c524bb1a88b396390098dc451565567e37532ba03
5
5
  SHA512:
6
- metadata.gz: e309cedd41919e03dbd6b3db209cc5d0cef9cb2dc8c9308abf6de414ce87c4ef5b55157ef51fdd867cab03bac9773c08d36ec10868daa9e13b1914357b66e25e
7
- data.tar.gz: fb16ec608debaf7cd0caf5c9b662969617b9fad57ebbe65e620c1ffcab2008218199f9472d3a6ba9a72433ea24457e5c24d6c4902f3ac2f9909f98cef8df1f6c
6
+ metadata.gz: a8206e2599b2cd9556e2ff9eb03a5789bd87aa73d2776edce7f35c02c1bde56497838d7dece88e05a986775df1a21371d2ef1adf37a7aef75ed6a442e5fe0c5a
7
+ data.tar.gz: e0b5eeaff73cc4530c70cd6c3f054b561948feaa4e845f31b29c496f465c2d73de6d822d4828b740b40ced23fd85658cbbfc5f5120fc2c564ae343bb2fc4b551
data/CHANGELOG.md CHANGED
@@ -1,4 +1,9 @@
1
- ## 0.4.0
1
+ ## 0.5.0
2
+ - Add support for slots
3
+ - Change @props to only add valid variable names to global scope
4
+ - Change @props to remove from attributes array
5
+
6
+ ## 0.4.0 [2024-07-29]
2
7
  - Add @class and @style statements
3
8
  - Add @env and @production statements
4
9
  - Add @once, @pushOnce and @prependOnce statements
data/README.md CHANGED
@@ -31,9 +31,9 @@ Hello, {{ name }}.
31
31
  ```
32
32
 
33
33
  > [!NOTE]
34
- > RBlade's `{{ }}` echo statements are automatically sent through Rails' `h` function to prevent XSS attacks.
34
+ > RBlade's `{{ }}` print statements are automatically sent through Rails' `h` function to prevent XSS attacks.
35
35
 
36
- You are not limited to displaying the contents of the variables passed to the view. You may also print the results of any Ruby function. In fact, you can put any Ruby code you wish inside of a Blade echo statement:
36
+ You are not limited to displaying the contents of the variables passed to the view. You may also print the results of any Ruby function. In fact, you can put any Ruby code you wish inside of a RBlade print directive:
37
37
 
38
38
  ```rblade
39
39
  The current UNIX timestamp is {{ Time.now.to_i }}.
@@ -77,7 +77,7 @@ The `@` symbol may also be used to escape RBlade directives:
77
77
  <a name="the-at-verbatim-directive"></a>
78
78
  #### The `@verbatim` Directive
79
79
 
80
- If you are displaying JavaScript variables in a large portion of your template, you may wrap the HTML in the `@verbatim` directive so that you do not have to prefix each Blade echo statement with an `@` symbol:
80
+ If you are displaying JavaScript variables in a large portion of your template, you may wrap the HTML in the `@verbatim` directive so that you do not have to prefix each Blade print directive with an `@` symbol:
81
81
 
82
82
  ```rblade
83
83
  @verbatim
@@ -530,7 +530,7 @@ You can pass data to RBlade components using HTML attributes. Hard-coded strings
530
530
 
531
531
  #### Component Properties
532
532
 
533
- You can define a component's data properties using a `@props` statement at the top of the component. You can then reference these properties using local variables within the template:
533
+ You can define a component's data properties using a `@props` directive at the top of the component. You can then reference these properties using local variables within the template:
534
534
 
535
535
  ```rblade
536
536
  {{-- alert.rblade --}}
@@ -538,25 +538,18 @@ You can define a component's data properties using a `@props` statement at the t
538
538
  <div class="{{ type }}">{{ message }}</div>
539
539
  ```
540
540
 
541
- The `@props` statement accepts a `Hash` where the key is the name of the attribute, and the value is the default value for the property. You can use the special `_required` value to represent a property with no default that must always be defined:
541
+ The `@props` directive accepts a `Hash` where the key is the name of the attribute, and the value is the default value for the property. You can use the special `_required` value to represent a property with no default that must always be defined:
542
542
 
543
543
  ```rblade
544
544
  {{-- This will give an error because the alert component requires a message propery --}}
545
545
  <x-alert/>
546
546
  ```
547
547
 
548
- Kebab-case properties can be referenced using underscores in place of the dashes:
548
+ All properties in the `@props` directive are automatically removed from `attributes`. Properties with names that aren't valid Ruby variable names or are Ruby reserved keywords are not created as local variables. However, you can reference them via the `attributes` local variable:
549
549
 
550
550
  ```rblade
551
- @props({"data-value": _required})
552
- <div>{{ data_value }}</div>
553
- ```
554
-
555
- Properties that contain other non-alphanumeric characters or are Ruby reserved keywords are not created as local variables. However, you can reference them via the `attributes` local variable:
556
-
557
- ```rblade
558
- @props({"for": _required})
559
- <div>{{ attributes[:for] }}</div>
551
+ @props({"for": _required, "data-value": nil})
552
+ <div>{{ attributes[:for] }} {{ attributes[:'data-value'] }}</div>
560
553
  ```
561
554
 
562
555
  <a name="short-attribute-syntax"></a>
@@ -774,11 +767,11 @@ We may pass content to the `slot` by injecting content into the component:
774
767
  </x-alert>
775
768
  ```
776
769
 
777
- **TODO this**
778
770
  Sometimes a component may need to render multiple different slots in different locations within the component. Let's modify our alert component to allow for the injection of a "title" slot:
779
771
 
780
772
  ```rblade
781
773
  {{-- /app/views/components/alert.rblade --}}
774
+ @props({title: _required})
782
775
  <span class="alert-title">{{ title }}</span>
783
776
  <div class="alert alert-danger">
784
777
  {{ slot }}
@@ -796,7 +789,7 @@ You may define the content of the named slot using the `x-slot` tag. Any content
796
789
  <strong>Whoops!</strong> Something went wrong!
797
790
  </x-alert>
798
791
  ```
799
-
792
+ **TODO this**
800
793
  You may invoke a slot's `isEmpty` method to determine if the slot contains content:
801
794
 
802
795
  ```rblade
@@ -26,17 +26,16 @@ module RBlade
26
26
  private
27
27
 
28
28
  def compile_token_start token
29
- @component_count += 1
30
-
31
- @component_stack << {
29
+ component = {
32
30
  name: token.value[:name],
33
- index: @component_count
31
+ index: @component_stack.count
34
32
  }
33
+ @component_stack << component
35
34
 
36
35
  attributes = compile_attributes token.value[:attributes]
37
36
 
38
- code = "_c#{@component_count}_swap=_out;_out='';"
39
- code << "_c#{@component_count}_attr={#{attributes.join(",")}};"
37
+ code = "_c#{component[:index]}_swap=_out;_out='';"
38
+ code << "_c#{component[:index]}_attr={#{attributes.join(",")}};"
40
39
 
41
40
  code
42
41
  end
@@ -50,15 +49,34 @@ module RBlade
50
49
  raise StandardError.new "Unexpected closing tag (#{token.value[:name]}) expecting #{component[:name]}"
51
50
  end
52
51
 
53
- code = "_slot=_out;_out=_c#{component[:index]}_swap;"
54
- code << "_out<<#{ComponentStore.component(component[:name])}(_slot,_c#{component[:index]}_attr);"
55
- code << "_slot=nil;_c#{component[:index]}_swap=nil;"
52
+ namespace = nil
53
+ name = component[:name]
54
+ if name.match '::'
55
+ namespace, name = component[:name].split("::")
56
+ end
57
+
58
+ code = if namespace == 'slot'
59
+ compile_slot_end name, component
60
+ else
61
+ compile_component_end component
62
+ end
63
+ end
64
+
65
+ def compile_slot_end name, component
66
+ parent = @component_stack.last
67
+
68
+ code = "_c#{parent[:index]}_attr[:'#{RBlade.escape_quotes(name)}']=RBlade::SlotManager.new(_out,_c#{component[:index]}_attr);"
69
+ code << "_out=_c#{component[:index]}_swap;_c#{component[:index]}_swap=nil;_c#{component[:index]}_attr=nil;"
56
70
 
57
71
  code
58
72
  end
59
73
 
60
- def get_method_name name
61
- name.gsub(/[^a-zA-Z0-9_]/, "_")
74
+ def compile_component_end component
75
+ code = "_slot=RBlade::SlotManager.new(_out);_out=_c#{component[:index]}_swap;"
76
+ code << "_out<<#{ComponentStore.component(component[:name])}(_slot,_c#{component[:index]}_attr);"
77
+ code << "_slot=nil;_c#{component[:index]}_swap=nil;_c#{component[:index]}_attr=nil;"
78
+
79
+ code
62
80
  end
63
81
 
64
82
  def compile_attributes attributes
@@ -8,8 +8,8 @@ module RBlade
8
8
  private
9
9
 
10
10
  def compile_regular_echos!(tokens)
11
- compile_echos! tokens, "{{", "}}", "h"
12
- compile_echos! tokens, "<%=", "%>", "h"
11
+ compile_echos! tokens, "{{", "}}", "RBlade.e"
12
+ compile_echos! tokens, "<%=", "%>", "RBlade.e"
13
13
  end
14
14
 
15
15
  def compile_unsafe_echos!(tokens)
@@ -35,8 +35,8 @@ module RBlade
35
35
  segments.delete_at i
36
36
  segments.delete_at i + 1
37
37
  segment_value = "_out<<"
38
- # Special case for slot and attributes - we want this to be able to output HTML
39
- segment_value <<= if !wrapper_function.nil? && segments[i] != "slot" && !segments[i].start_with?("attributes")
38
+
39
+ segment_value <<= if !wrapper_function.nil?
40
40
  wrapper_function + "(" + segments[i] + ");"
41
41
  else
42
42
  "(" + segments[i] + ").to_s;"
@@ -10,14 +10,23 @@ module RBlade
10
10
 
11
11
  props = extractProps args[0]
12
12
  props.map do |key, value|
13
+ compiled_code = ""
13
14
  if value == "_required"
14
- "if !defined?(#{key})&&!attributes.has?(:'#{RBlade.escape_quotes(key)}');raise \"Props statement: #{key} is not defined\";end;#{key.sub(/[^a-zA-Z0-9_]/, "_")}=attributes.default(:'#{RBlade.escape_quotes(key)}');"
15
+ compiled_code << "if !attributes.has?(:'#{RBlade.escape_quotes(key)}');raise \"Props statement: #{key} is not defined\";end;"
16
+ end
17
+ if isValidVariableName key
18
+ compiled_code << "#{key}=attributes[:'#{RBlade.escape_quotes(key)}'].nil? ? #{value} : attributes[:'#{RBlade.escape_quotes(key)}'];"
19
+ compiled_code << "attributes.delete :'#{RBlade.escape_quotes(key)}';"
15
20
  else
16
- "#{key.sub(/[^a-zA-Z0-9_]/, "_")}=attributes.default(:'#{RBlade.escape_quotes(key)}',#{value});"
21
+ compiled_code << "attributes.default(:'#{RBlade.escape_quotes(key)}', #{value});"
17
22
  end
23
+
24
+ compiled_code
18
25
  end.join
19
26
  end
20
27
 
28
+ private
29
+
21
30
  def extractProps prop_string
22
31
  if !prop_string.start_with?("{") || !prop_string.end_with?("}")
23
32
  raise StandardError.new "Props statement: expecting hash as parameter"
@@ -31,9 +40,9 @@ module RBlade
31
40
 
32
41
  key, value = prop.split(/^
33
42
  (?:
34
- ('.+'):
43
+ '(.+)':
35
44
  |
36
- (".+"):
45
+ "(.+)":
37
46
  |
38
47
  ([^ :]+):
39
48
  |
@@ -56,6 +65,16 @@ module RBlade
56
65
 
57
66
  props
58
67
  end
68
+
69
+ RUBY_RESERVED_KEYWORDS = %w[__FILE__ __LINE__ alias and begin BEGIN break case class def defined? do else elsif end END ensure false for if in module next nil not or redo rescue retry return self super then true undef unless until when while yield].freeze
70
+
71
+ def isValidVariableName key
72
+ return false unless key.match?(/^[a-zA-Z_][a-zA-Z0-9_]*$/)
73
+
74
+ return false if RUBY_RESERVED_KEYWORDS.include? key
75
+
76
+ true
77
+ end
59
78
  end
60
79
  end
61
80
  end
@@ -6,6 +6,7 @@ require "rblade/compiler/compiles_verbatim"
6
6
  require "rblade/compiler/compiles_statements"
7
7
  require "rblade/compiler/tokenizes_components"
8
8
  require "rblade/compiler/tokenizes_statements"
9
+ require "rblade/helpers/html_string"
9
10
 
10
11
  Token = Struct.new(:type, :value)
11
12
 
@@ -19,6 +20,14 @@ module RBlade
19
20
  string.gsub(/['\\\x0]/, '\\\\\0')
20
21
  end
21
22
 
23
+ def self.e string
24
+ if string.is_a? HtmlString
25
+ string
26
+ else
27
+ h(string)
28
+ end
29
+ end
30
+
22
31
  class Compiler
23
32
  def self.compileString(string_template)
24
33
  tokens = [Token.new(:unprocessed, string_template)]
@@ -1,5 +1,7 @@
1
+ require "rblade/helpers/html_string"
2
+
1
3
  module RBlade
2
- class AttributesManager
4
+ class AttributesManager < HtmlString
3
5
  @attributes = {}
4
6
  def initialize attributes
5
7
  @attributes = attributes
@@ -33,6 +35,10 @@ module RBlade
33
35
  end.join " "
34
36
  end
35
37
 
38
+ def to_str
39
+ to_s
40
+ end
41
+
36
42
  def only(keys)
37
43
  keys = if keys.is_a? Array
38
44
  keys.map(&:to_sym)
@@ -0,0 +1,4 @@
1
+ module RBlade
2
+ class HtmlString
3
+ end
4
+ end
@@ -0,0 +1,23 @@
1
+ require "rblade/helpers/attributes_manager"
2
+ require "rblade/helpers/html_string"
3
+
4
+ module RBlade
5
+ class SlotManager < HtmlString
6
+ def initialize content, attributes = nil
7
+ @content = content
8
+ @attributes = attributes && AttributesManager.new(attributes)
9
+ end
10
+
11
+ def to_s
12
+ @content
13
+ end
14
+
15
+ def to_str
16
+ to_s
17
+ end
18
+
19
+ def attributes
20
+ @attributes
21
+ end
22
+ end
23
+ end
@@ -46,6 +46,10 @@ module RBlade
46
46
  "#{@before_stack}#{@prepends}#{@stack}"
47
47
  end
48
48
 
49
+ def to_str
50
+ to_s
51
+ end
52
+
49
53
  def push code
50
54
  @stack << code
51
55
  end
@@ -3,6 +3,7 @@ require "rblade/compiler"
3
3
  require "rblade/component_store"
4
4
  require "rblade/helpers/attributes_manager"
5
5
  require "rblade/helpers/class_manager"
6
+ require "rblade/helpers/slot_manager"
6
7
  require "rblade/helpers/stack_manager"
7
8
  require "rblade/helpers/style_manager"
8
9
 
data/rblade.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "rblade"
3
- s.version = "0.4.0"
3
+ s.version = "0.5.0"
4
4
  s.summary = "A component-first templating engine for Rails"
5
5
  s.description = "RBlade is a simple, yet powerful templating engine for Ruby on Rails, inspired by Laravel Blade."
6
6
  s.authors = ["Simon J"]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rblade
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon J
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-29 00:00:00.000000000 Z
11
+ date: 2024-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -103,6 +103,8 @@ files:
103
103
  - lib/rblade/component_store.rb
104
104
  - lib/rblade/helpers/attributes_manager.rb
105
105
  - lib/rblade/helpers/class_manager.rb
106
+ - lib/rblade/helpers/html_string.rb
107
+ - lib/rblade/helpers/slot_manager.rb
106
108
  - lib/rblade/helpers/stack_manager.rb
107
109
  - lib/rblade/helpers/style_manager.rb
108
110
  - lib/rblade/helpers/tokenizer.rb