Skip to content

Commit 8988cbe

Browse files
authored
Merge pull request #3590 from AlchemyCMS/fix-elements-generator
Fix elements generator
2 parents c075f8e + 0fab3b4 commit 8988cbe

File tree

6 files changed

+163
-13
lines changed

6 files changed

+163
-13
lines changed

app/models/alchemy/element_definition.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class ElementDefinition
3636
format: {with: /\A[\w-]+\z/i},
3737
if: -> { icon.is_a?(String) }
3838

39+
delegate :[], to: :attributes
3940
delegate :blank?, to: :name
4041

4142
DEFAULT_ICON_NAME = "layout-bottom-2-line"

app/models/alchemy/ingredient_definition.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class IngredientDefinition
3333
with: /\A[A-Z][a-zA-Z]+\z/
3434
}
3535

36+
delegate :[], to: :attributes
3637
delegate :blank?, to: :role
3738

3839
def attributes

lib/generators/alchemy/elements/elements_generator.rb

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,11 @@ class ElementsGenerator < Base
99
source_root File.expand_path("templates", __dir__)
1010

1111
def create_partials
12-
@elements = load_alchemy_yaml("elements.yml")
13-
return unless @elements
14-
12+
@elements = Alchemy::ElementDefinition.all
1513
@elements.each do |element|
1614
@element = element
17-
@ingredients = element["ingredients"] || []
18-
@element_name = element_name(element)
15+
@ingredients = element.ingredients
16+
@element_name = element.name
1917
conditional_template "view.html.#{template_engine}", "#{elements_dir}/_#{@element_name}.html.#{template_engine}"
2018
end
2119
end
@@ -25,14 +23,6 @@ def create_partials
2523
def elements_dir
2624
@_elements_dir ||= "app/views/alchemy/elements"
2725
end
28-
29-
def element_name(element)
30-
if Alchemy::Element::NAME_REGEXP.match?(element["name"])
31-
element["name"].underscore
32-
else
33-
raise "Element name '#{element["name"]}' has wrong format. Only lowercase and non whitespace characters allowed."
34-
end
35-
end
3626
end
3727
end
3828
end
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# frozen_string_literal: true
2+
3+
require "rails_helper"
4+
require "active_support/testing/stream"
5+
require "generators/alchemy/elements/elements_generator"
6+
7+
RSpec.describe Alchemy::Generators::ElementsGenerator do
8+
include ActiveSupport::Testing::Stream
9+
10+
around do |example|
11+
Dir.mktmpdir do |dir|
12+
@destination = Pathname.new(dir)
13+
Dir.chdir(@destination) do
14+
example.run
15+
end
16+
end
17+
end
18+
19+
let(:destination) { @destination }
20+
let(:elements_dir) { destination.join("app/views/alchemy/elements") }
21+
let(:generator_args) { [] }
22+
23+
subject(:run_generator) do
24+
capture(:stdout) do
25+
described_class.start(generator_args, destination_root: destination)
26+
end
27+
end
28+
29+
describe "#create_partials" do
30+
before do
31+
allow(Alchemy::ElementDefinition).to receive(:all).and_return(elements)
32+
end
33+
34+
context "with elements defined" do
35+
let(:elements) do
36+
[
37+
Alchemy::ElementDefinition.new(
38+
name: "article",
39+
ingredients: [{"role" => "headline", "type" => "Headline"}]
40+
),
41+
Alchemy::ElementDefinition.new(
42+
name: "sidebar",
43+
ingredients: []
44+
)
45+
]
46+
end
47+
48+
it "creates a partial for each element" do
49+
run_generator
50+
51+
expect(elements_dir.join("_article.html.erb")).to exist
52+
expect(elements_dir.join("_sidebar.html.erb")).to exist
53+
end
54+
55+
it "generates partials with element_view_for and element name as variable" do
56+
run_generator
57+
58+
content = elements_dir.join("_article.html.erb").read
59+
expect(content).to include("element_view_for(article)")
60+
end
61+
end
62+
63+
context "with underscored element names" do
64+
let(:elements) do
65+
[Alchemy::ElementDefinition.new(name: "featured_article", ingredients: [])]
66+
end
67+
68+
it "preserves underscores in the partial filename" do
69+
run_generator
70+
71+
expect(elements_dir.join("_featured_article.html.erb")).to exist
72+
end
73+
end
74+
75+
context "when ElementDefinition.all returns empty array" do
76+
let(:elements) { [] }
77+
78+
it "does not create any partials" do
79+
run_generator
80+
81+
expect(Dir.glob(elements_dir.join("_*.html.erb"))).to be_empty
82+
end
83+
end
84+
85+
context "with slim template engine" do
86+
let(:elements) { [Alchemy::ElementDefinition.new(name: "article", ingredients: [])] }
87+
let(:generator_args) { ["-e", "slim"] }
88+
89+
it "creates slim partials" do
90+
run_generator
91+
92+
expect(elements_dir.join("_article.html.slim")).to exist
93+
end
94+
end
95+
96+
context "with haml template engine" do
97+
let(:elements) { [Alchemy::ElementDefinition.new(name: "article", ingredients: [])] }
98+
let(:generator_args) { ["-e", "haml"] }
99+
100+
it "creates haml partials" do
101+
run_generator
102+
103+
expect(elements_dir.join("_article.html.haml")).to exist
104+
end
105+
end
106+
107+
context "with nestable elements" do
108+
let(:elements) do
109+
[Alchemy::ElementDefinition.new(
110+
name: "container",
111+
ingredients: [],
112+
nestable_elements: ["nested_item"]
113+
)]
114+
end
115+
116+
it "includes nested elements rendering in the partial" do
117+
run_generator
118+
119+
content = elements_dir.join("_container.html.erb").read
120+
expect(content).to include("nested_elements")
121+
end
122+
end
123+
124+
context "when partial already exists with different template engine" do
125+
let(:elements) { [Alchemy::ElementDefinition.new(name: "existing", ingredients: [])] }
126+
let(:generator_args) { ["--force"] }
127+
128+
before do
129+
FileUtils.mkdir_p(elements_dir)
130+
elements_dir.join("_existing.html.slim").write("= element_view_for(existing)")
131+
end
132+
133+
it "uses the existing template engine instead of the default" do
134+
expect(run_generator).to include("warning", "slim")
135+
expect(elements_dir.join("_existing.html.erb")).not_to exist
136+
expect(elements_dir.join("_existing.html.slim")).to exist
137+
end
138+
end
139+
end
140+
end

spec/models/alchemy/element_definition_spec.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@
44

55
module Alchemy
66
describe ElementDefinition do
7+
describe "#[]" do
8+
let(:definition) { described_class.new(name: "article", unique: true) }
9+
10+
it "provides hash-like access to attributes" do
11+
expect(definition["name"]).to eq("article")
12+
expect(definition[:unique]).to be(true)
13+
end
14+
end
15+
716
describe "#attributes" do
817
let(:definition) { described_class.new(name: "standard") }
918

spec/models/alchemy/ingredient_definition_spec.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@
44

55
module Alchemy
66
describe IngredientDefinition do
7+
describe "#[]" do
8+
let(:definition) { described_class.new(role: "headline", type: "Headline") }
9+
10+
it "provides hash-like access to attributes" do
11+
expect(definition["role"]).to eq("headline")
12+
expect(definition[:type]).to eq("Headline")
13+
end
14+
end
15+
716
describe "#attributes" do
817
let(:definition) { described_class.new(role: "text") }
918

0 commit comments

Comments
 (0)