mime-components 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 27afc059f5c4f3436849f350d1b6046bec7f784a1b8d16dade5a899294dc4511
4
+ data.tar.gz: faab2883fe9bec8083c59b9fd0777b8de85b70257a3a1f866d37081f497021a9
5
+ SHA512:
6
+ metadata.gz: dde53597426f25ea0ac45f05b8b06fe436d6ebc8a19412f74dcc4b80a0eca379268a647d1630af5b228b1354b99a3a07d774ab78a4e72e22b4a6f1f4a776245a
7
+ data.tar.gz: b96bf72013f2fc318a2d8a75d4bab5b96ef7b278a2f493909b1f911aebb71c60df4be7bb9bdb252c9729fafddd4902badd79874eb39f7d59751e40b48afb6a90
@@ -0,0 +1,17 @@
1
+ # Built-in components.
2
+ # frozen_string_literal: true
3
+
4
+
5
+ module Mime
6
+ # Register default components to an engine. This is done when an engine is
7
+ # initialized and generally should not be done externally.
8
+ # @param engine(Mime::Engine) engine to register default components to
9
+ def self.register_defaults(engine)
10
+ component_variable = Mime::Component.new('Variable') do |attributes, vars|
11
+ value = vars[attributes[:name].to_s.to_sym]
12
+ value = Erubi.h(value) unless Component.attr_true?(attributes[:raw])
13
+ value
14
+ end
15
+ engine.register_component(component_variable)
16
+ end
17
+ end
@@ -0,0 +1,66 @@
1
+ # Component system.
2
+ # frozen_string_literal: true
3
+
4
+
5
+ module Mime
6
+ # A component is a class with a 'render' function. This function's output
7
+ # will replace the final XML in the rendered document.
8
+ class Component
9
+ @name, @proc = nil
10
+
11
+ # Check if an attribute's value is truthy.
12
+ # @param value(String|Symbol) attribute to check
13
+ # @return (True|False) whether or not the value is truthy
14
+ def self.attr_true?(value)
15
+ [1, 'true', 'yes'].include?(value.to_s.strip.downcase)
16
+ end
17
+
18
+ # Create a new component.
19
+ # @param name(String) component name
20
+ # @param proc(Proc) block to call on invocation
21
+ def initialize(name, &proc)
22
+ @name = name
23
+ @proc = proc
24
+ end
25
+
26
+ # Call this component's rendering function.
27
+ # @param attributes(Hash) rendering parameters
28
+ # @param vars(Hash) template variables
29
+ # @return (String) rendered component
30
+ def render(attributes, vars)
31
+ @proc.call(attributes, vars)
32
+ end
33
+
34
+ attr_reader :name
35
+ end
36
+
37
+ class Engine
38
+ @registered_components = {}
39
+
40
+ # Register a new component for this engine.
41
+ # @param component(Component) component to register
42
+ def register_component(component)
43
+ @registered_components[component.name.downcase] = component
44
+ end
45
+
46
+ # Render a component based on its parsed XML tag.
47
+ # @param name(String) component name
48
+ # @param xml(String) raw component XML
49
+ # @param vars(Hash) variables to pass to component
50
+ def render_component(name, xml, vars)
51
+ # get component, raising an error if it doesn't exist
52
+ if (component = @registered_components[name.downcase]).nil?
53
+ raise "#{xml}: component '#{name}' was not registered for this engine"
54
+ end
55
+
56
+ # normalize attributes
57
+ xml = Nokogiri::XML.parse(xml).root
58
+ attributes = {}
59
+ xml.attributes.map do |k, v|
60
+ attributes[k.to_s.strip.downcase.to_sym] = v
61
+ end
62
+ # render subcomponents of output
63
+ render(component.render(attributes, vars).to_s, vars)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,17 @@
1
+ # Engine class and initializer.
2
+ # frozen_string_literal: true
3
+
4
+
5
+ module Mime
6
+ # The Engine is the primary class responsible for rendering Mime documents. Each
7
+ # engine contains a component registry as well as a set of built-in components.
8
+ class Engine
9
+ # Initialize a new instance of the Mime templating engine.
10
+ def initialize
11
+ @global_vars = {}
12
+ @registered_components = {}
13
+ @component_regex = %r{(<[MmCc]:((?:[A-z0-9\:\-]+)|\#).*?/?>)}
14
+ Mime.register_defaults(self)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,30 @@
1
+ # Global per-engine variables.
2
+ # frozen_string_literal: true
3
+
4
+
5
+ module Mime
6
+ class Engine
7
+ @global_vars = {}
8
+
9
+ # Set a global template variable.
10
+ # @param name(String) name of variable to set
11
+ # @param value(Object) new value of variable (nil to unset)
12
+ # @return (Object) new value
13
+ def []=(name, value)
14
+ @global_vars[name] = value
15
+ end
16
+
17
+ # Get a global template variable.
18
+ # @param name(String) name of variable to get value of
19
+ # @return (Object) value
20
+ def [](name)
21
+ @global_vars[name]
22
+ end
23
+
24
+ # Get a list of set global variables.
25
+ # @return (Array[Object]) set keys
26
+ def keys
27
+ @global_vars.keys
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,36 @@
1
+ # Component tag location and rendering.
2
+ # frozen_string_literal: true
3
+
4
+
5
+ module Mime
6
+ class Engine
7
+ # Render all components in a 'template'.
8
+ # @param template(String) template as string
9
+ # @param vars(Hash) variables to render with
10
+ def render(template, vars)
11
+ @global_vars.each_key do |k|
12
+ vars[k] = @global_vars[k]
13
+ end
14
+ # we locate, parse and replace tags to render the template. none of these
15
+ # things work with frozen literals, so we'll make a copy to work on and return
16
+ output = template.dup
17
+ # find tags
18
+ matches = output.scan(@component_regex)
19
+ matches.each do |n|
20
+ # render tag
21
+ tag, component_name = n
22
+ tag_out = if component_name == '#'
23
+ ''
24
+ else
25
+ render_component(component_name, tag, vars)
26
+ end
27
+ # replace tag in output with its rendered value
28
+ output.gsub!(tag, tag_out)
29
+ end
30
+
31
+ # freeze and return output
32
+ output.freeze
33
+ output
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,42 @@
1
+ # Erubi templating support.
2
+ # frozen_string_literal: true
3
+
4
+
5
+ module Mime
6
+ # A component wrapped around a compiled Erubi template.
7
+ class ERBComponent < Component
8
+ @erubi_engine = nil
9
+ # Create a new Mime component from an Erubi template. XML arguments will be passed to this
10
+ # template as an instance variable named `@args`, and variables will be set as instance
11
+ # varibles (for example, ':my_variable' would be accessible as '@my_variable').
12
+ def initialize(name, template)
13
+ # pre-compile template
14
+ @erubi_engine = Erubi::Engine.new(template, freeze: true, escape: true)
15
+ # execute template in a new context with few variables
16
+ super(name) do |args, vars|
17
+ # george is a sandbox instance that can only access variables and arguments
18
+ # passed to the template by this component.
19
+ george = Object.new
20
+ # pass arguments
21
+ george.instance_variable_set(:@args, args)
22
+ # pass global variables
23
+ vars.each { |var| george.instance_variable_set(:"@#{var[0]}", var[1]) }
24
+ # pass instance variables
25
+ instance_variables.each { |var| george.instance_variable_set(var, instance_variable_get(var)) }
26
+ # evaluate template as george :)
27
+ george.instance_eval(@erubi_engine.src)
28
+ end
29
+ end
30
+ end
31
+
32
+ class Engine
33
+ # Render an ERB template with Erubi, then post-process with this engine.
34
+ # @param template(Erubi::Engine) rendered ERB template
35
+ # @param vars(Hash) map of variables to send to template
36
+ # @return (String) rendered template
37
+ def erb(template, vars)
38
+ template_output = instance_eval(template.src)
39
+ render(template_output, vars)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ # Let it be known that I do not like Gems
3
+
4
+ # Mime is a component (not templating!) system based on XML tags (components).
5
+ module Mime
6
+ require 'erubi'
7
+ require 'nokogiri'
8
+ require_relative 'mime-components/components/builtins'
9
+ require_relative 'mime-components/components/components'
10
+ require_relative 'mime-components/engine/engine'
11
+ require_relative 'mime-components/engine/globals'
12
+ require_relative 'mime-components/engine/render'
13
+ require_relative 'mime-components/extensions/erb'
14
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mime-components
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - talkingsodapop
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-11-08 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A post-processing component system
14
+ email: tobskep@aol.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/mime-components.rb
20
+ - lib/mime-components/components/builtins.rb
21
+ - lib/mime-components/components/components.rb
22
+ - lib/mime-components/engine/engine.rb
23
+ - lib/mime-components/engine/globals.rb
24
+ - lib/mime-components/engine/render.rb
25
+ - lib/mime-components/extensions/erb.rb
26
+ homepage: https://rubygems.org/gems/mime-components
27
+ licenses:
28
+ - LGPL-2.1-or-later
29
+ metadata:
30
+ rubygems_mfa_required: 'true'
31
+ post_install_message:
32
+ rdoc_options: []
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '2.7'
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ requirements: []
46
+ rubygems_version: 3.5.16
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: Mime
50
+ test_files: []