ruby-exclaim 0.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 +7 -0
- data/.circleci/config.yml +43 -0
- data/.github/workflows/release.yml +29 -0
- data/.gitignore +12 -0
- data/.overcommit.yml +13 -0
- data/.rspec +3 -0
- data/.rubocop.yml +12 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +806 -0
- data/Rakefile +10 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/exclaim.rb +32 -0
- data/lib/exclaim/bind.rb +28 -0
- data/lib/exclaim/component.rb +7 -0
- data/lib/exclaim/errors.rb +23 -0
- data/lib/exclaim/helper.rb +7 -0
- data/lib/exclaim/implementable.rb +14 -0
- data/lib/exclaim/implementation_map.rb +93 -0
- data/lib/exclaim/implementations/each_component.rb +32 -0
- data/lib/exclaim/implementations/example_implementation_map.rb +31 -0
- data/lib/exclaim/implementations/if_helper.rb +28 -0
- data/lib/exclaim/implementations/image_component.rb +12 -0
- data/lib/exclaim/implementations/join_helper.rb +12 -0
- data/lib/exclaim/implementations/let_component.rb +16 -0
- data/lib/exclaim/implementations/paragraph_component.rb +15 -0
- data/lib/exclaim/implementations/text_component.rb +8 -0
- data/lib/exclaim/implementations/vbox_component.rb +22 -0
- data/lib/exclaim/railtie.rb +11 -0
- data/lib/exclaim/renderer.rb +65 -0
- data/lib/exclaim/ui.rb +127 -0
- data/lib/exclaim/ui_configuration.rb +139 -0
- data/lib/exclaim/utilities.rb +20 -0
- data/lib/exclaim/version.rb +5 -0
- data/ruby-exclaim.gemspec +42 -0
- metadata +166 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Exclaim
|
4
|
+
class Renderer
|
5
|
+
def initialize(parsed_ui)
|
6
|
+
@parsed_ui = parsed_ui
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env: {})
|
10
|
+
top_level_component = @parsed_ui
|
11
|
+
render_element(top_level_component, env)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def render_element(element, env)
|
17
|
+
case element
|
18
|
+
in Component => component
|
19
|
+
resolved_config = resolve_component_config(component, env)
|
20
|
+
render_child = method(:render_element)
|
21
|
+
component.implementation.call(resolved_config, env, &render_child)
|
22
|
+
else
|
23
|
+
resolve(element, env)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def resolve_component_config(component, env)
|
28
|
+
resolve(component.config, env).transform_values! { |value| escape_html!(value) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def escape_html!(value)
|
32
|
+
case value
|
33
|
+
when String
|
34
|
+
CGI.escape_html(value)
|
35
|
+
when Hash
|
36
|
+
value.transform_values! { |v| escape_html!(v) }
|
37
|
+
when Array
|
38
|
+
value.map! { |v| escape_html!(v) }
|
39
|
+
when Numeric, TrueClass, FalseClass, NilClass
|
40
|
+
value
|
41
|
+
else
|
42
|
+
# assumed to be a custom wrapper class returned by a helper
|
43
|
+
value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def resolve(element, env)
|
48
|
+
case element
|
49
|
+
in Component => component
|
50
|
+
component # will be resolved by calling its implementation later
|
51
|
+
in Bind => bind
|
52
|
+
bind.evaluate(env)
|
53
|
+
in Helper => helper
|
54
|
+
resolved_helper_config = resolve(helper.config, env)
|
55
|
+
helper.implementation.call(resolved_helper_config, env)
|
56
|
+
in Hash => hash
|
57
|
+
hash.transform_values { |value| resolve(value, env) }
|
58
|
+
in Array => array
|
59
|
+
array.map { |item| resolve(item, env) }
|
60
|
+
else
|
61
|
+
element
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/exclaim/ui.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Exclaim
|
4
|
+
class Ui
|
5
|
+
attr_reader :implementation_map, :parsed_ui, :renderer
|
6
|
+
|
7
|
+
def initialize(implementation_map: Exclaim::Implementations.example_implementation_map)
|
8
|
+
@implementation_map = Exclaim::ImplementationMap.parse!(implementation_map)
|
9
|
+
rescue Exclaim::Error
|
10
|
+
raise
|
11
|
+
rescue StandardError => e
|
12
|
+
e.extend(Exclaim::InternalError)
|
13
|
+
raise
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse_ui!(ui_config)
|
17
|
+
self.parsed_ui = Exclaim::UiConfiguration.parse!(@implementation_map, ui_config)
|
18
|
+
rescue Exclaim::Error
|
19
|
+
raise
|
20
|
+
rescue StandardError => e
|
21
|
+
e.extend(Exclaim::InternalError)
|
22
|
+
raise
|
23
|
+
end
|
24
|
+
|
25
|
+
def render(env: {})
|
26
|
+
if parsed_ui.nil?
|
27
|
+
error_message = 'Cannot render without UI configured, must call Exclaim::Ui#parse_ui(ui_config) first'
|
28
|
+
raise RenderingError.new(error_message)
|
29
|
+
end
|
30
|
+
|
31
|
+
renderer.call(env: env)
|
32
|
+
rescue Exclaim::Error
|
33
|
+
raise
|
34
|
+
rescue StandardError => e
|
35
|
+
e.extend(Exclaim::InternalError)
|
36
|
+
raise
|
37
|
+
end
|
38
|
+
|
39
|
+
def unique_bind_paths
|
40
|
+
if parsed_ui.nil?
|
41
|
+
error_message = 'Cannot compute unique_bind_paths without UI configured, ' \
|
42
|
+
'must call Exclaim::Ui#parse_ui(ui_config) first'
|
43
|
+
raise UiConfigurationError.new(error_message)
|
44
|
+
end
|
45
|
+
|
46
|
+
parsed_ui.config.reduce([]) { |all_paths, config_value| bind_paths(config_value, all_paths) }.uniq!
|
47
|
+
end
|
48
|
+
|
49
|
+
def each_element(element_names = :ALL_ELEMENTS, &blk)
|
50
|
+
if parsed_ui.nil?
|
51
|
+
error_message = 'Cannot compute each_element without UI configured, ' \
|
52
|
+
'must call Exclaim::Ui#parse_ui(ui_config) first'
|
53
|
+
raise UiConfigurationError.new(error_message)
|
54
|
+
end
|
55
|
+
normalized_element_names = parse_element_names(element_names)
|
56
|
+
|
57
|
+
if block_given?
|
58
|
+
top_level_component = parsed_ui
|
59
|
+
recurse_json_declarations(top_level_component, normalized_element_names, &blk)
|
60
|
+
else
|
61
|
+
to_enum(__callee__)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def parsed_ui=(value)
|
68
|
+
@parsed_ui = value
|
69
|
+
@renderer = Exclaim::Renderer.new(@parsed_ui)
|
70
|
+
end
|
71
|
+
|
72
|
+
def bind_paths(config_value, accumulator)
|
73
|
+
case config_value
|
74
|
+
in Hash => hash
|
75
|
+
hash.values.each { |val| bind_paths(val, accumulator) }
|
76
|
+
in Array => array
|
77
|
+
array.each { |val| bind_paths(val, accumulator) }
|
78
|
+
in Bind => bind
|
79
|
+
accumulator.push(bind.path)
|
80
|
+
in Helper | Component => element
|
81
|
+
bind_paths(element.config, accumulator)
|
82
|
+
else
|
83
|
+
nil
|
84
|
+
end
|
85
|
+
|
86
|
+
accumulator
|
87
|
+
end
|
88
|
+
|
89
|
+
def parse_element_names(element_names)
|
90
|
+
case element_names
|
91
|
+
when :ALL_ELEMENTS
|
92
|
+
:ALL_ELEMENTS
|
93
|
+
when String
|
94
|
+
[normalize_name(element_names)]
|
95
|
+
when Array
|
96
|
+
element_names.map { |en| normalize_name(en) }
|
97
|
+
else
|
98
|
+
raise UiConfigurationError.new('Exclaim::Ui#each_element: element_names argument ' \
|
99
|
+
"must be a String or Array, given #{element_names.class}")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def normalize_name(element_name)
|
104
|
+
element_name.start_with?('$') ? element_name[1..] : element_name
|
105
|
+
end
|
106
|
+
|
107
|
+
def recurse_json_declarations(config_value, element_names, &blk)
|
108
|
+
case config_value
|
109
|
+
in Bind => bind
|
110
|
+
yield bind.json_declaration if element_matches?(element_names, 'bind')
|
111
|
+
in Component | Helper => element
|
112
|
+
yield element.json_declaration if element_matches?(element_names, element.name)
|
113
|
+
element.config.each_value { |val| recurse_json_declarations(val, element_names, &blk) }
|
114
|
+
in Array => array
|
115
|
+
array.each { |val| recurse_json_declarations(val, element_names, &blk) }
|
116
|
+
in Hash => hash
|
117
|
+
hash.each_value { |val| recurse_json_declarations(val, element_names, &blk) }
|
118
|
+
else
|
119
|
+
nil
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def element_matches?(requested_element_names, parsed_element_name)
|
124
|
+
requested_element_names == :ALL_ELEMENTS || requested_element_names.include?(parsed_element_name)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Exclaim
|
4
|
+
module UiConfiguration
|
5
|
+
extend self
|
6
|
+
|
7
|
+
EXPLICIT_ELEMENT_NAMES = ['$component', '$helper', '$bind'].freeze
|
8
|
+
|
9
|
+
def parse!(implementation_map, ui_config)
|
10
|
+
raise UiConfigurationError.new("ui_config must be a Hash, given: #{ui_config.class}") unless ui_config.is_a?(Hash)
|
11
|
+
|
12
|
+
parsed_ui = parse_config_value(implementation_map, ui_config)
|
13
|
+
|
14
|
+
unless parsed_ui.is_a?(Exclaim::Component)
|
15
|
+
error_message = 'ui_config must declare a component at the top-level that is present in implementation_map'
|
16
|
+
raise UiConfigurationError.new(error_message)
|
17
|
+
end
|
18
|
+
|
19
|
+
parsed_ui
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def parse_config_value(implementation_map, config_value)
|
25
|
+
case config_value
|
26
|
+
in Hash => hash
|
27
|
+
parse_config_hash(implementation_map, hash)
|
28
|
+
in Array => array
|
29
|
+
array.map { |value| parse_config_value(implementation_map, value) }
|
30
|
+
else
|
31
|
+
config_value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse_config_hash(implementation_map, config_hash)
|
36
|
+
# config_hash will be either an Exclaim element declaration or just plain configuration values
|
37
|
+
element_name = parse_element_name(implementation_map, config_hash)
|
38
|
+
if element_name.nil?
|
39
|
+
config_hash.transform_values { |val| parse_config_value(implementation_map, val) }
|
40
|
+
else
|
41
|
+
parse_element(implementation_map, element_name, config_hash)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse_element(implementation_map, element_name, element_declaration_hash)
|
46
|
+
implementation = implementation_map[element_name]
|
47
|
+
|
48
|
+
if helper?(implementation)
|
49
|
+
config = parse_element_config(implementation_map, element_declaration_hash)
|
50
|
+
Exclaim::Helper.new(json_declaration: element_declaration_hash,
|
51
|
+
name: element_name,
|
52
|
+
implementation: implementation,
|
53
|
+
config: config)
|
54
|
+
elsif component?(implementation)
|
55
|
+
config = parse_element_config(implementation_map, element_declaration_hash)
|
56
|
+
Exclaim::Component.new(json_declaration: element_declaration_hash,
|
57
|
+
name: element_name,
|
58
|
+
implementation: implementation,
|
59
|
+
config: config)
|
60
|
+
else
|
61
|
+
Exclaim::Bind.new(json_declaration: element_declaration_hash, path: element_declaration_hash['$bind'])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def parse_element_config(implementation_map, element_declaration_hash)
|
66
|
+
element_declaration_hash.each_with_object({}) do |(key, val), parsed_element_config|
|
67
|
+
parsed_element_config[key] = if ['$component', '$helper'].include?(key)
|
68
|
+
val
|
69
|
+
else
|
70
|
+
parse_config_value(implementation_map, val)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def parse_element_name(implementation_map, config_hash)
|
76
|
+
candidate_names = config_hash.keys.filter_map do |key|
|
77
|
+
key[1..] if key.start_with?('$') && !EXPLICIT_ELEMENT_NAMES.include?(key)
|
78
|
+
end
|
79
|
+
candidate_names.reject! do |name|
|
80
|
+
unrecognized = implementation_map[name].nil?
|
81
|
+
Exclaim.logger.warn("ui_config includes key \"$#{name}\" which has no matching implementation") if unrecognized
|
82
|
+
unrecognized
|
83
|
+
end
|
84
|
+
|
85
|
+
explicit_component_name = parse_explicit_declaration(implementation_map, config_hash, '$component')
|
86
|
+
explicit_helper_name = parse_explicit_declaration(implementation_map, config_hash, '$helper')
|
87
|
+
|
88
|
+
candidate_names.push(explicit_component_name, explicit_helper_name)
|
89
|
+
candidate_names.compact!
|
90
|
+
|
91
|
+
# binds do not have implementations, but they are still special Exclaim elements
|
92
|
+
candidate_names.push('bind') if config_hash.include?('$bind')
|
93
|
+
|
94
|
+
if candidate_names.count > 1
|
95
|
+
error_message = "Multiple Exclaim elements defined at one configuration level: #{candidate_names}. " \
|
96
|
+
'Only one allowed.'
|
97
|
+
raise UiConfigurationError.new(error_message)
|
98
|
+
end
|
99
|
+
|
100
|
+
# returns nil when config_hash is not an Exclaim element declaration
|
101
|
+
candidate_names.first
|
102
|
+
end
|
103
|
+
|
104
|
+
def parse_explicit_declaration(implementation_map, config_hash, explicit_key)
|
105
|
+
explicit_name = config_hash[explicit_key]
|
106
|
+
return nil if explicit_name.nil?
|
107
|
+
|
108
|
+
if explicit_name.start_with?('$')
|
109
|
+
error_message = "Invalid: \"#{explicit_key}\": \"#{explicit_name}\", " \
|
110
|
+
"when declaring explicit \"#{explicit_key}\" do not prefix the name with \"$\""
|
111
|
+
raise UiConfigurationError.new(error_message)
|
112
|
+
end
|
113
|
+
|
114
|
+
if implementation_map[explicit_name].nil?
|
115
|
+
error_message = "ui_config declares \"#{explicit_key}\": \"#{explicit_name}\" " \
|
116
|
+
'which has no matching implementation'
|
117
|
+
raise UiConfigurationError.new(error_message)
|
118
|
+
end
|
119
|
+
|
120
|
+
explicit_name
|
121
|
+
end
|
122
|
+
|
123
|
+
def component?(element)
|
124
|
+
element_type(element) == 'component'
|
125
|
+
end
|
126
|
+
|
127
|
+
def helper?(element)
|
128
|
+
element_type(element) == 'helper'
|
129
|
+
end
|
130
|
+
|
131
|
+
def element_type(element)
|
132
|
+
if element.respond_to?(:component?)
|
133
|
+
element.component? ? 'component' : 'helper'
|
134
|
+
elsif element.respond_to?(:helper?)
|
135
|
+
element.helper? ? 'helper' : 'component'
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Exclaim
|
4
|
+
module Utilities
|
5
|
+
def element_name(config_hash)
|
6
|
+
unless config_hash.is_a?(Hash)
|
7
|
+
error_message = "Exclaim.element_name can only determine name from a Hash, given #{config_hash.class} value"
|
8
|
+
Exclaim.logger.warn(error_message)
|
9
|
+
return
|
10
|
+
end
|
11
|
+
|
12
|
+
return config_hash['$component'] if config_hash.include?('$component')
|
13
|
+
return config_hash['$helper'] if config_hash.include?('$helper')
|
14
|
+
return 'bind' if config_hash.include?('$bind')
|
15
|
+
|
16
|
+
shorthand_name = config_hash.keys.find { |key| key.start_with?('$') }
|
17
|
+
shorthand_name&.[](1..)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'exclaim/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'ruby-exclaim'
|
9
|
+
spec.version = Exclaim::VERSION
|
10
|
+
spec.authors = ['Salsify, Inc']
|
11
|
+
spec.email = ['engineering@salsify.com']
|
12
|
+
|
13
|
+
spec.summary = 'Ruby utilities for Exclaim UIs'
|
14
|
+
spec.description = spec.summary
|
15
|
+
spec.homepage = 'https://github.com/salsify/ruby-exclaim'
|
16
|
+
|
17
|
+
spec.license = 'MIT'
|
18
|
+
|
19
|
+
|
20
|
+
# Set 'allowed_push_post' to control where this gem can be published.
|
21
|
+
if spec.respond_to?(:metadata)
|
22
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
23
|
+
|
24
|
+
else
|
25
|
+
raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
|
26
|
+
end
|
27
|
+
|
28
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
29
|
+
spec.bindir = 'bin'
|
30
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
31
|
+
spec.require_paths = ['lib']
|
32
|
+
|
33
|
+
spec.required_ruby_version = '>= 2.7'
|
34
|
+
|
35
|
+
spec.add_development_dependency 'bundler', '~> 2.0'
|
36
|
+
spec.add_development_dependency 'overcommit'
|
37
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
38
|
+
spec.add_development_dependency 'rspec', '~> 3.9'
|
39
|
+
spec.add_development_dependency 'rspec_junit_formatter', '~> 0.4.1'
|
40
|
+
|
41
|
+
spec.add_development_dependency 'salsify_rubocop', '~> 1.0'
|
42
|
+
end
|
metadata
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby-exclaim
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Salsify, Inc
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-03-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: overcommit
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '13.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '13.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.9'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.9'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec_junit_formatter
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.4.1
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.4.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: salsify_rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.0'
|
97
|
+
description: Ruby utilities for Exclaim UIs
|
98
|
+
email:
|
99
|
+
- engineering@salsify.com
|
100
|
+
executables:
|
101
|
+
- console
|
102
|
+
- setup
|
103
|
+
extensions: []
|
104
|
+
extra_rdoc_files: []
|
105
|
+
files:
|
106
|
+
- ".circleci/config.yml"
|
107
|
+
- ".github/workflows/release.yml"
|
108
|
+
- ".gitignore"
|
109
|
+
- ".overcommit.yml"
|
110
|
+
- ".rspec"
|
111
|
+
- ".rubocop.yml"
|
112
|
+
- CHANGELOG.md
|
113
|
+
- Gemfile
|
114
|
+
- LICENSE.txt
|
115
|
+
- README.md
|
116
|
+
- Rakefile
|
117
|
+
- bin/console
|
118
|
+
- bin/setup
|
119
|
+
- lib/exclaim.rb
|
120
|
+
- lib/exclaim/bind.rb
|
121
|
+
- lib/exclaim/component.rb
|
122
|
+
- lib/exclaim/errors.rb
|
123
|
+
- lib/exclaim/helper.rb
|
124
|
+
- lib/exclaim/implementable.rb
|
125
|
+
- lib/exclaim/implementation_map.rb
|
126
|
+
- lib/exclaim/implementations/each_component.rb
|
127
|
+
- lib/exclaim/implementations/example_implementation_map.rb
|
128
|
+
- lib/exclaim/implementations/if_helper.rb
|
129
|
+
- lib/exclaim/implementations/image_component.rb
|
130
|
+
- lib/exclaim/implementations/join_helper.rb
|
131
|
+
- lib/exclaim/implementations/let_component.rb
|
132
|
+
- lib/exclaim/implementations/paragraph_component.rb
|
133
|
+
- lib/exclaim/implementations/text_component.rb
|
134
|
+
- lib/exclaim/implementations/vbox_component.rb
|
135
|
+
- lib/exclaim/railtie.rb
|
136
|
+
- lib/exclaim/renderer.rb
|
137
|
+
- lib/exclaim/ui.rb
|
138
|
+
- lib/exclaim/ui_configuration.rb
|
139
|
+
- lib/exclaim/utilities.rb
|
140
|
+
- lib/exclaim/version.rb
|
141
|
+
- ruby-exclaim.gemspec
|
142
|
+
homepage: https://github.com/salsify/ruby-exclaim
|
143
|
+
licenses:
|
144
|
+
- MIT
|
145
|
+
metadata:
|
146
|
+
allowed_push_host: https://rubygems.org
|
147
|
+
post_install_message:
|
148
|
+
rdoc_options: []
|
149
|
+
require_paths:
|
150
|
+
- lib
|
151
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
152
|
+
requirements:
|
153
|
+
- - ">="
|
154
|
+
- !ruby/object:Gem::Version
|
155
|
+
version: '2.7'
|
156
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - ">="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
requirements: []
|
162
|
+
rubygems_version: 3.2.11
|
163
|
+
signing_key:
|
164
|
+
specification_version: 4
|
165
|
+
summary: Ruby utilities for Exclaim UIs
|
166
|
+
test_files: []
|