Skip to content

Commit 48fe1ec

Browse files
authored
Merge pull request #252 from marcoroth/core_component_generator
Introduce Core Component Generator
2 parents 5b9a351 + 1ca560c commit 48fe1ec

File tree

9 files changed

+207
-0
lines changed

9 files changed

+207
-0
lines changed

docs/contribute/README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,29 @@ Feel free to take a look at other examples and copy their structure!
2222
Note: We will not approve pull requests that introduce new concepts or components without documentation. Same goes for existing concepts & components.
2323
If you change the behavior of an existing part of this project, make sure to also update the corresponding part of the documentation!
2424

25+
## Core Components
26+
27+
Core Components are an essential part of the `matestack-ui-core` gem.
28+
If you are planning to contribute to Matestack you can start doing that by creating a core component. To help you getting started you can use the Core Component Generator.
29+
30+
The generator will create a matestack core component to `app/concepts/matestack/ui/core`.
31+
32+
Example:
33+
34+
```bash
35+
rails generate matestack:core:component div
36+
```
37+
38+
This will create a component for the HTML `<div>` tag and will generate the following files:
39+
40+
```bash
41+
app/concepts/matestack/ui/core/div/div.haml
42+
app/concepts/matestack/ui/core/div/div.rb
43+
spec/usage/components/div_spec.rb
44+
docs/components/div.md
45+
```
46+
47+
2548
## Tests
2649

2750
To assure this project is and remains in great condition, we heavily rely on automated tests. Tests are defined in `/spec` folder and can be executed by running:
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Description:
2+
This generates a matestack core component in app/concepts/matestack, a spec file and a docs file.
3+
4+
Pass the name of the component under_scored.
5+
6+
Example 1:
7+
`rails generate matestack:core:component NAME`
8+
9+
This will create:
10+
app/concepts/matestack/ui/core/NAME/NAME.haml
11+
app/concepts/matestack/ui/core/NAME/NAME.rb
12+
spec/usage/components/NAME_spec.rb
13+
docs/components/NAME.md
14+
15+
This will insert a link to the docs in:
16+
docs/components/README.md
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# frozen_string_literal: true
2+
3+
module Matestack
4+
module Core
5+
module Generators
6+
class ComponentGenerator < Rails::Generators::NamedBase
7+
source_root File.expand_path('templates', __dir__)
8+
9+
def create_core_component
10+
template 'app/concepts/matestack/ui/core/%file_name%/%file_name%.haml'
11+
template 'app/concepts/matestack/ui/core/%file_name%/%file_name%.rb'
12+
template 'spec/usage/components/%file_name%_spec.rb'
13+
template 'docs/components/%file_name%.md'
14+
15+
inject_into_file 'docs/components/README.md', before: "\n## Dynamic Core Components\n" do <<~RUBY
16+
- [#{file_name.underscore}](/docs/components/#{file_name.underscore}.md)
17+
RUBY
18+
end
19+
end
20+
end
21+
end
22+
end
23+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
%<%= file_name.underscore %>{@tag_attributes}
2+
- if options[:text].blank? && block_given?
3+
= yield
4+
- else
5+
= options[:text]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module Matestack::Ui::Core::<%= file_name.camelcase %>
2+
class <%= file_name.camelcase %> < Matestack::Ui::Core::Component::Static
3+
end
4+
end
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# matestack core component: <%= file_name.camelcase %>
2+
3+
Show [specs](/spec/usage/components/<%= file_name.underscore %>_spec.rb)
4+
5+
The HTML `<<%= file_name.underscore %>>` tag implemented in ruby.
6+
7+
## Parameters
8+
9+
This component can take 2 optional configuration params and either yield content or display what gets passed to the `text` configuration param.
10+
11+
#### # id (optional)
12+
Expects a string with all ids the `<<%= file_name.underscore %>>` should have.
13+
14+
#### # class (optional)
15+
Expects a string with all classes the `<<%= file_name.underscore %>>` should have.
16+
17+
## Example 1: Yield a given block
18+
19+
```ruby
20+
<%= file_name.underscore %> id: 'foo', class: 'bar' do
21+
plain '<%= file_name.camelcase %> example 1' # optional content
22+
end
23+
```
24+
25+
returns
26+
27+
```html
28+
<<%= file_name.underscore %> id="foo" class="bar">
29+
<%= file_name.camelcase %> example 1
30+
</<%= file_name.underscore %>>
31+
```
32+
33+
## Example 2: Render `options[:text]` param
34+
35+
```ruby
36+
<%= file_name.underscore %> id: 'foo', class: 'bar', text: '<%= file_name.camelcase %> example 2'
37+
```
38+
39+
returns
40+
41+
```html
42+
<<%= file_name.underscore %> id="foo" class="bar">
43+
<%= file_name.camelcase %> example 2
44+
</<%= file_name.underscore %>>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
require_relative '../../support/utils'
2+
include Utils
3+
4+
describe '<%= file_name.camelcase %> component', type: :feature, js: true do
5+
it 'Renders a simple and enhanced <%= file_name.underscore %> tag on a page' do
6+
class ExamplePage < Matestack::Ui::Page
7+
def response
8+
components {
9+
# Simple <%= file_name.underscore %>
10+
<%= file_name.underscore %> text: 'Simple <%= file_name.underscore %> tag'
11+
12+
# Enhanced <%= file_name.underscore %>
13+
<%= file_name.underscore %> id: 'my-id', class: 'my-class' do
14+
plain 'Enhanced <%= file_name.underscore %> tag'
15+
end
16+
}
17+
end
18+
end
19+
20+
visit '/example'
21+
22+
static_output = page.html
23+
24+
expected_static_output = <<~HTML
25+
<<%= file_name.underscore %>>Simple <%= file_name.underscore %> tag</<%= file_name.underscore %>>
26+
<<%= file_name.underscore %> id="my-id" class="my-class">Enhanced <%= file_name.underscore %> tag</<%= file_name.underscore %>>
27+
HTML
28+
29+
expect(stripped(static_output)).to include(stripped(expected_static_output))
30+
end
31+
end

spec/dummy/docs/components/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Core Components
2+
3+
matestack provides a wide set of core components, which enables you to easily build your UI.
4+
You can build your [own components](/docs/extend/custom_components.md) as well, either static or dynamic.
5+
6+
## Static Core Components
7+
8+
- [br](/docs/components/br.md)
9+
- [img](/docs/components/img.md)
10+
11+
## Dynamic Core Components
12+
13+
- [transition](/docs/components/transition.md)
14+
- [onclick](/docs/components/onclick.md)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# frozen_string_literal: true
2+
3+
require 'generator_spec'
4+
require 'generators/matestack/core/component/component_generator'
5+
6+
describe Matestack::Core::Generators::ComponentGenerator, type: :generator do
7+
let(:dummy) { File.expand_path(File.join(__FILE__, '..', '..', '..', '..', '..', '..', 'dummy')) }
8+
let(:dummy_copy) { File.expand_path(File.join(__FILE__, '..', '..', '..', '..', '..', '..', 'dummy_copy')) }
9+
10+
before :each do
11+
FileUtils.cp_r dummy, dummy_copy
12+
end
13+
14+
after :each do
15+
FileUtils.rm_rf dummy
16+
FileUtils.cp_r dummy_copy, dummy
17+
FileUtils.rm_rf dummy_copy
18+
end
19+
20+
destination Rails.root
21+
22+
it 'creates a core component' do
23+
run_generator %w(div)
24+
25+
assert_file 'app/concepts/matestack/ui/core/div/div.rb', /module Matestack::Ui::Core::Div/
26+
assert_file 'app/concepts/matestack/ui/core/div/div.rb', /class Div < Matestack::Ui::Core::Component::Static/
27+
28+
assert_file 'app/concepts/matestack/ui/core/div/div.haml', /%div{@tag_attributes}/
29+
30+
assert_file 'spec/usage/components/div_spec.rb', /describe 'Div component', type: :feature, js: true do/
31+
assert_file 'spec/usage/components/div_spec.rb', /div text: 'Simple div tag'/
32+
assert_file 'spec/usage/components/div_spec.rb', %r{<div>Simple div tag</div>}
33+
assert_file 'spec/usage/components/div_spec.rb', /div id: 'my-id', class: 'my-class' do/
34+
assert_file 'spec/usage/components/div_spec.rb', %r{<div id="my-id" class="my-class">Enhanced div tag</div>}
35+
36+
assert_file 'docs/components/div.md', /# matestack core component: Div/
37+
assert_file 'docs/components/div.md', %r{Show \[specs\]\(/spec/usage/components/div_spec.rb\)}
38+
assert_file 'docs/components/div.md', /The HTML `<div>` tag implemented in ruby./
39+
assert_file 'docs/components/div.md', /Expects a string with all ids the `<div>` should have./
40+
assert_file 'docs/components/div.md', /Expects a string with all classes the `<div>` should have./
41+
assert_file 'docs/components/div.md', /div id: 'foo', class: 'bar' do/
42+
assert_file 'docs/components/div.md', /div id: 'foo', class: 'bar', text: 'Div example 2'/
43+
assert_file 'docs/components/div.md', /<div id="foo" class="bar">/
44+
45+
assert_file 'docs/components/README.md', %r{- \[div\]\(/docs/components/div.md\)}
46+
end
47+
end

0 commit comments

Comments
 (0)