vident 0.6.3 → 0.8.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 +4 -4
- data/README.md +224 -38
- data/Rakefile +1 -12
- data/lib/tasks/vident_tasks.rake +4 -0
- data/lib/vident/attributes/not_typed.rb +3 -0
- data/lib/vident/base.rb +8 -29
- data/lib/vident/component.rb +0 -2
- data/lib/vident/engine.rb +15 -0
- data/lib/vident/root_component.rb +235 -0
- data/lib/vident/version.rb +1 -1
- data/lib/vident.rb +3 -36
- metadata +11 -28
- data/.standard.yml +0 -3
- data/CHANGELOG.md +0 -69
- data/CODE_OF_CONDUCT.md +0 -84
- data/Gemfile +0 -34
- data/LICENSE.txt +0 -21
- data/examples/ex1.gif +0 -0
- data/lib/tasks/vident.rake +0 -37
- data/lib/vident/attributes/typed.rb +0 -229
- data/lib/vident/attributes/typed_niling_struct.rb +0 -27
- data/lib/vident/attributes/types.rb +0 -16
- data/lib/vident/caching/cache_key.rb +0 -145
- data/lib/vident/railtie.rb +0 -10
- data/lib/vident/root_component/base.rb +0 -237
- data/lib/vident/root_component/using_better_html.rb +0 -41
- data/lib/vident/root_component/using_phlex_html.rb +0 -49
- data/lib/vident/root_component/using_view_component.rb +0 -51
- data/lib/vident/test_case.rb +0 -8
- data/lib/vident/testing/attributes_tester.rb +0 -176
- data/lib/vident/testing/auto_test.rb +0 -70
- data/lib/vident/typed_component.rb +0 -48
- data/sig/vident.rbs +0 -4
@@ -1,41 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
if Gem.loaded_specs.has_key? "better_html"
|
4
|
-
require "better_html"
|
5
|
-
require "cgi/util"
|
6
|
-
|
7
|
-
module Vident
|
8
|
-
module RootComponent
|
9
|
-
module UsingBetterHTML
|
10
|
-
# Return the HTML `data-controller` attribute for the given controllers
|
11
|
-
def with_controllers(*controllers_to_set)
|
12
|
-
helpers.html_attributes("data-controller" => controller_list(controllers_to_set)&.html_safe)
|
13
|
-
end
|
14
|
-
|
15
|
-
# Return the HTML `data-target` attribute for the given targets
|
16
|
-
def as_targets(*targets)
|
17
|
-
attrs = build_target_data_attributes(parse_targets(targets))
|
18
|
-
helpers.html_attributes(attrs.transform_keys! { |k| "data-#{k}" })
|
19
|
-
end
|
20
|
-
alias_method :as_target, :as_targets
|
21
|
-
|
22
|
-
# Return the HTML `data-action` attribute for the given actions
|
23
|
-
def with_actions(*actions_to_set)
|
24
|
-
actions_str = action_list(actions_to_set)
|
25
|
-
actions_str.present? ? helpers.html_attributes("data-action" => actions_str) : nil
|
26
|
-
end
|
27
|
-
alias_method :with_action, :with_actions
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
# Complete list of actions ready to be use in the data-action attribute
|
32
|
-
def action_list(actions_to_parse)
|
33
|
-
return nil unless actions_to_parse&.size&.positive?
|
34
|
-
# `html_attributes` will escape '->' thus breaking the stimulus action, so we need to do our own escaping
|
35
|
-
actions_str_raw = parse_actions(actions_to_parse).join(" ")
|
36
|
-
CGI.escapeHTML(actions_str_raw).gsub("->", "->").html_safe
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
if Gem.loaded_specs.has_key? "phlex"
|
4
|
-
require "phlex"
|
5
|
-
|
6
|
-
module Vident
|
7
|
-
module RootComponent
|
8
|
-
class UsingPhlexHTML < Phlex::HTML
|
9
|
-
include Base
|
10
|
-
if Gem.loaded_specs.has_key? "better_html"
|
11
|
-
include UsingBetterHTML
|
12
|
-
end
|
13
|
-
|
14
|
-
VALID_TAGS = Set[
|
15
|
-
*(Phlex::HTML::VoidElements::REGISTERED_ELEMENTS.keys + Phlex::HTML::StandardElements::REGISTERED_ELEMENTS.keys)
|
16
|
-
].freeze
|
17
|
-
|
18
|
-
# Create a tag for a target with a block containing content
|
19
|
-
def target_tag(tag_name, targets, **options, &block)
|
20
|
-
parsed = parse_targets(Array.wrap(targets))
|
21
|
-
options[:data] ||= {}
|
22
|
-
options[:data].merge!(build_target_data_attributes(parsed))
|
23
|
-
generate_tag(tag_name, **options, &block)
|
24
|
-
end
|
25
|
-
|
26
|
-
# Build a tag with the attributes determined by this components properties and stimulus
|
27
|
-
# data attributes.
|
28
|
-
def template(&block)
|
29
|
-
# Generate tag options and render
|
30
|
-
tag_type = @element_tag.presence&.to_sym || :div
|
31
|
-
raise ArgumentError, "Unsupported HTML tag name #{tag_type}" unless VALID_TAGS.include?(tag_type)
|
32
|
-
options = @html_options&.dup || {}
|
33
|
-
data_attrs = tag_data_attributes
|
34
|
-
data_attrs = options[:data].present? ? data_attrs.merge(options[:data]) : data_attrs
|
35
|
-
options = options.merge(id: @id) if @id
|
36
|
-
options.except!(:data)
|
37
|
-
options.merge!(data_attrs.transform_keys { |k| "data-#{k}" })
|
38
|
-
generate_tag(tag_type, **options, &block)
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def generate_tag(tag_type, **options, &block)
|
44
|
-
send((tag_type == :template) ? :template_tag : tag_type, **options, &block)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
if Gem.loaded_specs.has_key? "view_component"
|
4
|
-
require "view_component"
|
5
|
-
|
6
|
-
module Vident
|
7
|
-
module RootComponent
|
8
|
-
class UsingViewComponent < ::ViewComponent::Base
|
9
|
-
include Base
|
10
|
-
if Gem.loaded_specs.has_key? "better_html"
|
11
|
-
include UsingBetterHTML
|
12
|
-
end
|
13
|
-
|
14
|
-
SELF_CLOSING_TAGS = Set[:area, :base, :br, :col, :embed, :hr, :img, :input, :link, :meta, :param, :source, :track, :wbr].freeze
|
15
|
-
|
16
|
-
def target_tag(tag_name, targets, **options, &block)
|
17
|
-
parsed = parse_targets(Array.wrap(targets))
|
18
|
-
options[:data] ||= {}
|
19
|
-
options[:data].merge!(build_target_data_attributes(parsed))
|
20
|
-
content = view_context.capture(&block) if block
|
21
|
-
view_context.content_tag(tag_name, content, options)
|
22
|
-
end
|
23
|
-
|
24
|
-
def call
|
25
|
-
# Generate outer tag options and render
|
26
|
-
tag_type = content_tag_type
|
27
|
-
options = content_tag_options
|
28
|
-
if SELF_CLOSING_TAGS.include?(tag_type)
|
29
|
-
view_context.tag(tag_type, options)
|
30
|
-
else
|
31
|
-
view_context.content_tag(tag_type, content, options)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def content_tag_options
|
38
|
-
options = @html_options&.dup || {}
|
39
|
-
data_attrs = tag_data_attributes
|
40
|
-
options[:data] = options[:data].present? ? data_attrs.merge(options[:data]) : data_attrs
|
41
|
-
return options unless @id
|
42
|
-
options.merge(id: @id)
|
43
|
-
end
|
44
|
-
|
45
|
-
def content_tag_type
|
46
|
-
@element_tag.presence || :div
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
data/lib/vident/test_case.rb
DELETED
@@ -1,176 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Vident
|
4
|
-
module Testing
|
5
|
-
class AttributesTester
|
6
|
-
def initialize(test_configurations)
|
7
|
-
@test_configurations = test_configurations
|
8
|
-
end
|
9
|
-
|
10
|
-
# Generates attribute hashes for all permutations of the given valid values.
|
11
|
-
def valid_configurations
|
12
|
-
# Expands any auto generated values and returns all attributes and their values
|
13
|
-
test_attrs = prepare_attributes_to_test
|
14
|
-
|
15
|
-
# The first permutation is the initial state
|
16
|
-
initial_state = prepare_initial_test_state(test_attrs)
|
17
|
-
|
18
|
-
# Create remaining permutations
|
19
|
-
test_attrs.flat_map do |attr_name, values|
|
20
|
-
values.map { |v| initial_state.merge(attr_name => v) }
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
# Generates attribute hashes for all permutations of the given invalid values.
|
25
|
-
def invalid_configurations
|
26
|
-
return [] unless invalid_configured?
|
27
|
-
|
28
|
-
# prepare a valid initial state, then add any attrs that have :invalid
|
29
|
-
initial_state = prepare_initial_test_state(prepare_attributes_to_test)
|
30
|
-
|
31
|
-
# Merge in the invalid permutations
|
32
|
-
test_configurations.inject([]) do |memo, attr|
|
33
|
-
key, opts = attr
|
34
|
-
next memo += nil if opts == :strict_boolean
|
35
|
-
if opts.is_a?(Hash)
|
36
|
-
values = if opts[:invalid].nil? && opts[:valid].is_a?(Hash)
|
37
|
-
# If no invalid key specified we generate based on whats valid
|
38
|
-
config = invalid_attribute_test_values_for(opts[:valid][:type], opts[:valid])
|
39
|
-
(config&.fetch(:invalid, []) || []) + (config&.fetch(:converts, []) || [])
|
40
|
-
elsif opts[:invalid].is_a?(Array)
|
41
|
-
opts[:invalid]
|
42
|
-
end
|
43
|
-
|
44
|
-
memo += values.map { |i| initial_state.merge(key => i) } if values
|
45
|
-
end
|
46
|
-
memo
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
attr_reader :test_configurations
|
53
|
-
|
54
|
-
def invalid_configured?
|
55
|
-
test_configurations.values.any? { |v| v.respond_to?(:key?) && v.key?(:invalid) }
|
56
|
-
end
|
57
|
-
|
58
|
-
def prepare_attributes_to_test
|
59
|
-
test_configurations.transform_values do |attr_config|
|
60
|
-
next [true, false, nil] if attr_config == :boolean
|
61
|
-
next [true, false] if attr_config == :strict_boolean
|
62
|
-
valid = attr_config[:valid]
|
63
|
-
raise "Ensure :valid attributes configuration is provided" unless valid
|
64
|
-
next valid if valid.is_a?(Array)
|
65
|
-
attribute_test_values_for(valid)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def prepare_initial_test_state(test_attrs)
|
70
|
-
initial_state = {}
|
71
|
-
test_attrs.each { |attr_name, values| initial_state[attr_name] = values.first }
|
72
|
-
initial_state
|
73
|
-
end
|
74
|
-
|
75
|
-
def attribute_test_values_for(options)
|
76
|
-
type = parse_type(options[:type])
|
77
|
-
return options[:in] if options[:in]
|
78
|
-
values =
|
79
|
-
case type
|
80
|
-
when :string, "String"
|
81
|
-
s = (1..8).map { |l| ::Faker::String.random(length: l) }
|
82
|
-
s.prepend "test string"
|
83
|
-
s = s.select(&:present?)
|
84
|
-
s << "" if options[:allow_blank]
|
85
|
-
s
|
86
|
-
when :boolean
|
87
|
-
[false, true]
|
88
|
-
when :float, "Float"
|
89
|
-
(1..3).map { Faker::Number.positive } + (1..3).map { Faker::Number.negative }
|
90
|
-
when :numeric, "Numeric"
|
91
|
-
(1..3).map { Faker::Number.positive } + [1, 5]
|
92
|
-
when :integer, "Integer"
|
93
|
-
min = options[:min] || -10_000
|
94
|
-
max = options[:max] || 10_000
|
95
|
-
(1..3).map { Kernel.rand(min..max) }
|
96
|
-
when :array, "Array"
|
97
|
-
a =
|
98
|
-
if options[:sub_type] == Numeric
|
99
|
-
[[1, 2, 3], [0.3, 2, 0.002]]
|
100
|
-
elsif options[:sub_type]
|
101
|
-
[[options[:sub_type].new]]
|
102
|
-
else
|
103
|
-
[%i[a b c], [1, 2, 3], %w[a b]]
|
104
|
-
end
|
105
|
-
a << [] if options[:allow_blank]
|
106
|
-
a
|
107
|
-
when :any
|
108
|
-
[false, 1245, {}, :df, "hi"]
|
109
|
-
when :hash, "Hash"
|
110
|
-
a = [{a: 1}]
|
111
|
-
a << {} if options[:allow_blank]
|
112
|
-
a
|
113
|
-
when :symbol, "Symbol"
|
114
|
-
%i[a b c]
|
115
|
-
else
|
116
|
-
raise StandardError, "Attribute type not understood (#{type})"
|
117
|
-
end
|
118
|
-
|
119
|
-
if options[:allow_nil] || !options[:default].nil? || (options[:allow_blank] && options[:allow_nil].nil?)
|
120
|
-
values << nil
|
121
|
-
end
|
122
|
-
values
|
123
|
-
end
|
124
|
-
|
125
|
-
def invalid_attribute_test_values_for(type, options)
|
126
|
-
values = case parse_type(type)
|
127
|
-
when :string, "String"
|
128
|
-
# All values are also convertable to string
|
129
|
-
a = {converts: [false, 1245, 1.0, {}, :df, []], invalid: []}
|
130
|
-
a[:invalid] << "" if options[:allow_blank] == false
|
131
|
-
a
|
132
|
-
when :boolean
|
133
|
-
# All values are also convertable to boolean with !!
|
134
|
-
{converts: ["sdf", 234, 3.5, {}, :sdf, []], invalid: []}
|
135
|
-
when :float, "Float"
|
136
|
-
# Not all values are convertable to float
|
137
|
-
{converts: [234, "12.2"], invalid: ["sdf", 234, {}, :sdf, [], false]}
|
138
|
-
when :numeric, "Numeric"
|
139
|
-
{converts: ["12.2"], invalid: ["sdf", {}, :sdf, [], false]}
|
140
|
-
when :integer, "Integer"
|
141
|
-
# Not all values are convertable to integer
|
142
|
-
{converts: [234.0, "123", "sdf"], invalid: [{}, :sdf, [], false]}
|
143
|
-
when :array, "Array"
|
144
|
-
# Not all values are convertable to array
|
145
|
-
a = if options[:sub_type]
|
146
|
-
{converts: [{}, [{}]], invalid: ["sdf", [123], [Class.new]]}
|
147
|
-
else
|
148
|
-
{converts: [{}], invalid: ["sdf", 234, 3.5, :sdf, false]}
|
149
|
-
end
|
150
|
-
a[:invalid] << [] if options[:allow_blank] == false
|
151
|
-
a
|
152
|
-
when :any
|
153
|
-
# There are no invalid values
|
154
|
-
{converts: [], invalid: []}
|
155
|
-
when :hash, "Hash"
|
156
|
-
a = {converts: [[], [[:a, 1], [:b, 2]]], invalid: [:sdf, false, "boo", 123]}
|
157
|
-
a[:invalid] << {} if options[:allow_blank] == false
|
158
|
-
a
|
159
|
-
when :symbol, "Symbol"
|
160
|
-
{converts: ["foo"], invalid: [{}, false, [], 123]}
|
161
|
-
else
|
162
|
-
raise StandardError, "Attribute type not understood (#{type})"
|
163
|
-
end
|
164
|
-
|
165
|
-
if options[:default].nil? && (!options[:allow_nil] || (!options[:allow_blank] && options[:allow_nil] != true))
|
166
|
-
values[:invalid] << nil
|
167
|
-
end
|
168
|
-
values
|
169
|
-
end
|
170
|
-
|
171
|
-
def parse_type(type)
|
172
|
-
type.is_a?(Symbol) ? type : type.name
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "minitest/hooks"
|
4
|
-
|
5
|
-
module Vident
|
6
|
-
module Testing
|
7
|
-
module AutoTest
|
8
|
-
extend ActiveSupport::Concern
|
9
|
-
|
10
|
-
included do
|
11
|
-
include Minitest::Hooks
|
12
|
-
|
13
|
-
def before_all
|
14
|
-
@results_content = []
|
15
|
-
::Vident::StableId.set_current_sequence_generator
|
16
|
-
end
|
17
|
-
|
18
|
-
def after_all
|
19
|
-
html = <<~HTML
|
20
|
-
<!doctype html>
|
21
|
-
<html lang="en">
|
22
|
-
<head>
|
23
|
-
<meta charset="UTF-8">
|
24
|
-
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
25
|
-
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
26
|
-
<title>Test run output</title>
|
27
|
-
</head>
|
28
|
-
<body>
|
29
|
-
#{@results_content.map(&:to_s).join("<hr>\n").html_safe}
|
30
|
-
</body>
|
31
|
-
</html>
|
32
|
-
HTML
|
33
|
-
|
34
|
-
# TODO: configurable layout
|
35
|
-
filename = self.class.name.gsub("::", "_")
|
36
|
-
File.write("render_results_#{filename}.html", html) # TODO: path for outputs (eg default tmp/)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
class_methods do
|
41
|
-
def auto_test(class_under_test, **param_config)
|
42
|
-
attribute_tester = Vident::Testing::AttributesTester.new(param_config)
|
43
|
-
attribute_tester.valid_configurations.each_with_index do |test, index|
|
44
|
-
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
45
|
-
def test_renders_with_valid_attrs_#{index}
|
46
|
-
test_attrs = #{test}
|
47
|
-
begin
|
48
|
-
@results_content << render_inline(#{class_under_test}.new(**test_attrs))
|
49
|
-
rescue => error
|
50
|
-
assert(false, "Should not raise with #{test.to_s.tr("\"", "'")} but did raise \#{error}")
|
51
|
-
end
|
52
|
-
end
|
53
|
-
RUBY
|
54
|
-
end
|
55
|
-
|
56
|
-
attribute_tester.invalid_configurations.each_with_index do |test, index|
|
57
|
-
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
58
|
-
def test_raises_with_invalid_attrs_#{index}
|
59
|
-
test_attrs = #{test}
|
60
|
-
assert_raises(StandardError, "Should raise with #{test.to_s.tr("\"", "'")}") do
|
61
|
-
@results_content << render_inline(#{class_under_test}.new(**test_attrs))
|
62
|
-
end
|
63
|
-
end
|
64
|
-
RUBY
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,48 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
if Gem.loaded_specs.has_key? "dry-struct"
|
4
|
-
require_relative "./attributes/typed"
|
5
|
-
|
6
|
-
module Vident
|
7
|
-
module TypedComponent
|
8
|
-
extend ActiveSupport::Concern
|
9
|
-
|
10
|
-
included do
|
11
|
-
include Vident::Base
|
12
|
-
include Vident::Attributes::Typed
|
13
|
-
|
14
|
-
attribute :id, String, delegates: false
|
15
|
-
attribute :html_options, Hash, delegates: false
|
16
|
-
attribute :element_tag, Symbol, delegates: false
|
17
|
-
|
18
|
-
# StimulusJS support
|
19
|
-
attribute :controllers, Array, default: [], delegates: false
|
20
|
-
attribute :actions, Array, default: [], delegates: false
|
21
|
-
attribute :targets, Array, default: [], delegates: false
|
22
|
-
attribute :data_maps, Array, default: [], delegates: false
|
23
|
-
|
24
|
-
# TODO normalise the syntax of defining actions, controllers, etc
|
25
|
-
attribute :named_classes, Hash, delegates: false
|
26
|
-
end
|
27
|
-
|
28
|
-
def initialize(attrs = {})
|
29
|
-
before_initialise(attrs)
|
30
|
-
prepare_attributes(attrs)
|
31
|
-
# The attributes need to also be set as ivars
|
32
|
-
attributes.each do |attr_name, attr_value|
|
33
|
-
instance_variable_set(self.class.attribute_ivar_names[attr_name], attr_value)
|
34
|
-
end
|
35
|
-
after_initialise
|
36
|
-
super()
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
else
|
41
|
-
module Vident
|
42
|
-
module TypedComponent
|
43
|
-
def self.included(base)
|
44
|
-
raise "Vident::TypedComponent requires dry-struct to be installed"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
data/sig/vident.rbs
DELETED