classy-yaml 1.3.1 → 1.4.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 +17 -0
- data/lib/classy/yaml/helpers.rb +87 -29
- data/lib/classy/yaml/version.rb +1 -1
- data/lib/classy/yaml.rb +84 -0
- metadata +45 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a6e53b93d281f5b22bc929c6b1df6f389fcd81ed4bc8b9bd3710830a1974ed1
|
4
|
+
data.tar.gz: 0702b4fe219583b61140e89487fb0f42c87b4f6de1c2b5889cbacc7186d546b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef1645ba8e34171a8b2a4eb24830789f5d3d412445e2bca83b6e30285a3a20fdd0911ac65388e092cd44197c3e1b9980bc0b565c8d4e623f72671c678ba1935f
|
7
|
+
data.tar.gz: c62c9a28bb4dc589fe04838f5ed33b6fcf27ee2dc68c833161f8e8a57ead9421ef78705c31f8baa546921de1366e247be4f3caf6e9e122720f428940a94e6246
|
data/README.md
CHANGED
@@ -85,6 +85,23 @@ btn:
|
|
85
85
|
|
86
86
|
# will add the classes "px-3 py-2 text-blue-50"
|
87
87
|
```
|
88
|
+
|
89
|
+
yass(:button, :primary) # => "btn btn-primary"
|
90
|
+
yass(:button, :secondary) # => "btn btn-secondary"
|
91
|
+
yass(:button, :large) # => "btn btn-lg"
|
92
|
+
yass(:button, :primary, :large) # => "btn btn-primary btn-lg"
|
93
|
+
|
94
|
+
### Array style definition
|
95
|
+
|
96
|
+
```
|
97
|
+
array:
|
98
|
+
- "px-3 py-2"
|
99
|
+
- "bg-gray"
|
100
|
+
- "text-purple"
|
101
|
+
```
|
102
|
+
|
103
|
+
yass(:array) # => "px-3 py-2 bg-gray text-purple"
|
104
|
+
|
88
105
|
## Configuration
|
89
106
|
You can configure the gem by creating an initializer in your Rails app. The following options are available:
|
90
107
|
|
data/lib/classy/yaml/helpers.rb
CHANGED
@@ -1,38 +1,69 @@
|
|
1
1
|
module Classy
|
2
2
|
module Yaml
|
3
3
|
module Helpers
|
4
|
+
# Fetches utility classes from YAML files based on the provided keys.
|
5
|
+
# The method follows a priority order:
|
6
|
+
# 1. Extra files (highest priority)
|
7
|
+
# 2. Default YAML
|
8
|
+
# 3. ViewComponent YAMLs (lowest priority)
|
9
|
+
#
|
10
|
+
# @param args [Array] Array of keys to look up in the YAML files
|
11
|
+
# @return [String] Space-separated list of CSS classes
|
4
12
|
def yass(*args)
|
5
|
-
|
13
|
+
# Start with ViewComponent YAMLs (lowest priority)
|
14
|
+
classy_yamls = Classy::Yaml.cached_engine_yamls.dup
|
6
15
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
classy_yamls << file if file
|
11
|
-
end
|
12
|
-
end
|
16
|
+
# Add default YAML (next priority)
|
17
|
+
default_yaml = Classy::Yaml.cached_default_yaml
|
18
|
+
classy_yamls << default_yaml if default_yaml
|
13
19
|
|
14
|
-
|
20
|
+
# Add extra files (highest priority)
|
21
|
+
Classy::Yaml.extra_files.each do |file_path|
|
22
|
+
load_yaml_file(file_path, classy_yamls, "extra")
|
23
|
+
end
|
15
24
|
|
25
|
+
# Add classy_files (highest priority)
|
16
26
|
classy_files_hash = args.find { |arg| arg.is_a?(Hash) && arg.keys.include?(:classy_files) } || { classy_files: [] }
|
17
|
-
|
18
|
-
|
19
|
-
if File.exist?(file) && YAML.load_file(file)
|
20
|
-
file = YAML.load_file(file)
|
21
|
-
classy_yamls << file if file
|
22
|
-
end
|
27
|
+
classy_files_hash[:classy_files].each do |file_path|
|
28
|
+
load_yaml_file(file_path, classy_yamls, "classy")
|
23
29
|
end
|
24
30
|
|
25
|
-
return if classy_yamls.blank?
|
31
|
+
return "" if classy_yamls.blank?
|
26
32
|
|
27
33
|
skip_base_hash = args.find { |arg| arg.is_a?(Hash) && arg.keys.include?(:skip_base) } || {}
|
28
34
|
keys, classes = flatten_args(values: args)
|
29
35
|
classes += fetch_classes(keys, classy_yamls: classy_yamls, skip_base: skip_base_hash[:skip_base])
|
30
36
|
|
31
|
-
|
37
|
+
classes.flatten.uniq.join(" ")
|
32
38
|
end
|
33
39
|
|
34
40
|
private
|
35
41
|
|
42
|
+
# Loads a YAML file and adds its contents to the classy_yamls array
|
43
|
+
# @param file_path [String, Pathname] Path to the YAML file
|
44
|
+
# @param classy_yamls [Array] Array to add the parsed YAML to
|
45
|
+
# @param file_type [String] Type of file being loaded (for error messages)
|
46
|
+
def load_yaml_file(file_path, classy_yamls, file_type)
|
47
|
+
begin
|
48
|
+
path_obj = file_path.is_a?(Pathname) ? file_path : Rails.root.join(file_path)
|
49
|
+
if File.exist?(path_obj)
|
50
|
+
content = File.read(path_obj, encoding: 'UTF-8')
|
51
|
+
parsed_yaml = YAML.safe_load(content, permitted_classes: [Symbol, String, Array, Hash], aliases: true)
|
52
|
+
classy_yamls << parsed_yaml if parsed_yaml && parsed_yaml.is_a?(Hash)
|
53
|
+
end
|
54
|
+
rescue Psych::SyntaxError => e
|
55
|
+
Rails.logger.error "Classy::Yaml (yass helper): Failed to parse #{file_type} YAML file #{file_path}: #{e.message}"
|
56
|
+
rescue => e
|
57
|
+
Rails.logger.error "Classy::Yaml (yass helper): Error loading #{file_type} YAML file #{file_path}: #{e.message}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Flattens the arguments into keys and classes
|
62
|
+
# @param root [Array] Current root path in the argument tree
|
63
|
+
# @param values [Array] Values to process
|
64
|
+
# @param keys [Array] Array to store found keys
|
65
|
+
# @param added_classes [Array] Array to store found classes
|
66
|
+
# @return [Array] Tuple of [keys, added_classes]
|
36
67
|
def flatten_args(root: [], values: [], keys: [], added_classes: [])
|
37
68
|
values.each do |value|
|
38
69
|
if value.is_a?(Hash)
|
@@ -57,6 +88,11 @@ module Classy
|
|
57
88
|
return keys, added_classes
|
58
89
|
end
|
59
90
|
|
91
|
+
# Fetches classes from the YAML files based on the provided keys
|
92
|
+
# @param keys [Array] Array of keys to look up
|
93
|
+
# @param classy_yamls [Array] Array of YAML files to search in
|
94
|
+
# @param skip_base [Boolean] Whether to skip base classes
|
95
|
+
# @return [Array] Array of found classes
|
60
96
|
def fetch_classes(keys, classy_yamls: [], skip_base: false)
|
61
97
|
classes = []
|
62
98
|
|
@@ -65,36 +101,58 @@ module Classy
|
|
65
101
|
fetched_classes = nil
|
66
102
|
|
67
103
|
classy_yamls.reverse_each do |classy_yaml|
|
104
|
+
# Base Class Lookup
|
68
105
|
unless skip_base == true
|
69
106
|
begin
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
107
|
+
value_at_key = classy_yaml.send(:dig, *key)
|
108
|
+
base_value = if value_at_key.is_a?(Hash)
|
109
|
+
classy_yaml.send(:dig, *(key + ['base']))
|
110
|
+
elsif key.length > 1
|
111
|
+
classy_yaml.send(:dig, *(key[0...-1] + ['base']))
|
112
|
+
else
|
113
|
+
nil
|
114
|
+
end
|
115
|
+
normalized_base = normalize_original(base_value)
|
116
|
+
base_classes ||= normalized_base
|
75
117
|
rescue
|
76
118
|
Rails.logger.warn(Classy::Yaml::InvalidKeyError.new(data: key))
|
77
119
|
end
|
78
120
|
end
|
79
121
|
|
122
|
+
# Specific Key Class Lookup
|
80
123
|
begin
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
fetched_classes = nil if fetched_classes.blank?
|
124
|
+
value = classy_yaml.send(:dig, *key)
|
125
|
+
unless value.is_a?(Hash)
|
126
|
+
normalized_fetched = normalize_original(value)
|
127
|
+
fetched_classes ||= normalized_fetched
|
128
|
+
end
|
87
129
|
rescue
|
88
130
|
Rails.logger.warn(Classy::Yaml::InvalidKeyError.new(data: key))
|
89
131
|
end
|
132
|
+
|
133
|
+
base_classes = nil if base_classes.blank?
|
134
|
+
fetched_classes = nil if fetched_classes.blank?
|
90
135
|
end
|
91
136
|
|
92
137
|
classes << base_classes unless base_classes.blank?
|
93
138
|
classes << fetched_classes unless fetched_classes.blank?
|
94
139
|
end
|
95
140
|
|
96
|
-
classes.
|
97
|
-
|
141
|
+
classes.flatten.uniq
|
142
|
+
end
|
143
|
+
|
144
|
+
# Normalizes a value into an array of classes
|
145
|
+
# @param value [String, Array, nil] Value to normalize
|
146
|
+
# @return [Array, nil] Array of classes or nil if value is invalid
|
147
|
+
def normalize_original(value)
|
148
|
+
case value
|
149
|
+
when String
|
150
|
+
value.split(" ").reject(&:blank?)
|
151
|
+
when Array
|
152
|
+
value.flatten.map(&:to_s).reject(&:blank?)
|
153
|
+
else
|
154
|
+
nil
|
155
|
+
end
|
98
156
|
end
|
99
157
|
end
|
100
158
|
end
|
data/lib/classy/yaml/version.rb
CHANGED
data/lib/classy/yaml.rb
CHANGED
@@ -3,6 +3,7 @@ require "classy/yaml/engine"
|
|
3
3
|
|
4
4
|
module Classy
|
5
5
|
module Yaml
|
6
|
+
# -- Configuration Accessors --
|
6
7
|
mattr_accessor :default_file
|
7
8
|
@@default_file = "config/utility_classes.yml"
|
8
9
|
|
@@ -12,20 +13,103 @@ module Classy
|
|
12
13
|
mattr_accessor :extra_files
|
13
14
|
@@extra_files = []
|
14
15
|
|
16
|
+
# -- Autoloads --
|
15
17
|
autoload :Helpers, "classy/yaml/helpers"
|
16
18
|
autoload :ComponentHelpers, "classy/yaml/component_helpers"
|
17
19
|
autoload :InvalidKeyError, "classy/yaml/invalid_key_error"
|
18
20
|
|
21
|
+
# -- Class Instance Variables for Caching --
|
22
|
+
@cached_engine_yamls = nil
|
23
|
+
@cached_default_yaml = nil
|
24
|
+
@load_lock = Mutex.new # Prevent race conditions during lazy loading
|
25
|
+
|
26
|
+
# -- Configuration Setters with Path Resolution --
|
19
27
|
def self.engine_files=(value)
|
20
28
|
@@engine_files = Array.wrap(value).reject(&:blank?).map { |file| Rails.root.join(file) }
|
29
|
+
@cached_engine_yamls = nil # Clear cache on reassignment
|
21
30
|
end
|
22
31
|
|
23
32
|
def self.extra_files=(value)
|
24
33
|
@@extra_files = Array.wrap(value).reject(&:blank?).map { |file| Rails.root.join(file) }
|
34
|
+
# Note: extra_files are not cached globally by default
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.default_file=(value)
|
38
|
+
@@default_file = value
|
39
|
+
@cached_default_yaml = nil # Clear cache on reassignment
|
40
|
+
end
|
41
|
+
|
42
|
+
# -- Cached Data Accessors (Lazy Loading) --
|
43
|
+
def self.cached_engine_yamls
|
44
|
+
# Bypass cache in development and test environments
|
45
|
+
return load_engine_yamls if Rails.env.development? || Rails.env.test?
|
46
|
+
|
47
|
+
# Use cache in other environments
|
48
|
+
return @cached_engine_yamls if @cached_engine_yamls
|
49
|
+
|
50
|
+
@load_lock.synchronize do
|
51
|
+
# Double-check idiom to ensure loading happens only once
|
52
|
+
return @cached_engine_yamls if @cached_engine_yamls
|
53
|
+
@cached_engine_yamls = load_engine_yamls
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.cached_default_yaml
|
58
|
+
# Bypass cache in development and test environments
|
59
|
+
return load_default_yaml if Rails.env.development? || Rails.env.test?
|
60
|
+
|
61
|
+
# Use cache in other environments
|
62
|
+
return @cached_default_yaml if @cached_default_yaml
|
63
|
+
|
64
|
+
@load_lock.synchronize do
|
65
|
+
return @cached_default_yaml if @cached_default_yaml
|
66
|
+
@cached_default_yaml = load_default_yaml
|
67
|
+
end
|
25
68
|
end
|
26
69
|
|
70
|
+
# -- Setup Method --
|
27
71
|
def self.setup
|
28
72
|
yield self
|
73
|
+
# Clear all caches when configuration changes
|
74
|
+
@cached_engine_yamls = nil
|
75
|
+
@cached_default_yaml = nil
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
# -- Private Loading Methods --
|
81
|
+
def self.load_engine_yamls
|
82
|
+
yamls = []
|
83
|
+
self.engine_files.each do |file_path|
|
84
|
+
begin
|
85
|
+
if File.exist?(file_path)
|
86
|
+
content = File.read(file_path, encoding: 'UTF-8')
|
87
|
+
parsed_yaml = YAML.safe_load(content, permitted_classes: [Symbol, String, Array, Hash], aliases: true)
|
88
|
+
yamls << parsed_yaml if parsed_yaml && parsed_yaml.is_a?(Hash)
|
89
|
+
end
|
90
|
+
rescue Psych::SyntaxError => e
|
91
|
+
Rails.logger.error "Classy::Yaml: Failed to parse engine YAML file #{file_path}: #{e.message}"
|
92
|
+
rescue => e
|
93
|
+
Rails.logger.error "Classy::Yaml: Error loading engine YAML file #{file_path}: #{e.message}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
yamls
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.load_default_yaml
|
100
|
+
default_path = Rails.root.join(self.default_file)
|
101
|
+
begin
|
102
|
+
if File.exist?(default_path)
|
103
|
+
content = File.read(default_path, encoding: 'UTF-8')
|
104
|
+
parsed_yaml = YAML.safe_load(content, permitted_classes: [Symbol, String, Array, Hash], aliases: true)
|
105
|
+
return parsed_yaml if parsed_yaml && parsed_yaml.is_a?(Hash)
|
106
|
+
end
|
107
|
+
rescue Psych::SyntaxError => e
|
108
|
+
Rails.logger.error "Classy::Yaml: Failed to parse default YAML file #{default_path}: #{e.message}"
|
109
|
+
rescue => e
|
110
|
+
Rails.logger.error "Classy::Yaml: Error loading default YAML file #{default_path}: #{e.message}"
|
111
|
+
end
|
112
|
+
nil # Return nil if file doesn't exist or fails to load/parse
|
29
113
|
end
|
30
114
|
end
|
31
115
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: classy-yaml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tonksthebear
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -80,6 +80,48 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '3.36'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: appraisal
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.60'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.60'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop-rails-omakase
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
83
125
|
description: Rails helper to allow yaml configuration of utility css classes
|
84
126
|
email:
|
85
127
|
- ''
|
@@ -120,7 +162,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
162
|
- !ruby/object:Gem::Version
|
121
163
|
version: '0'
|
122
164
|
requirements: []
|
123
|
-
rubygems_version: 3.
|
165
|
+
rubygems_version: 3.5.16
|
124
166
|
signing_key:
|
125
167
|
specification_version: 4
|
126
168
|
summary: Rails helper to allow yaml configuration of utility css classes
|