noumenon 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/.travis.yml +0 -4
- data/.yardopts +5 -0
- data/Gemfile +1 -3
- data/README.md +57 -80
- data/Rakefile +17 -6
- data/bin/noumenon +6 -0
- data/features/dynamic_template_rendering.feature +107 -0
- data/features/generator/site_generator.feature +25 -0
- data/features/mounted_applications.feature +30 -0
- data/features/static_template_rendering.feature +43 -0
- data/features/step_definitions/asset_steps.rb +7 -0
- data/features/step_definitions/content_steps.rb +7 -0
- data/features/step_definitions/generator_steps.rb +22 -0
- data/features/step_definitions/request_steps.rb +31 -0
- data/features/step_definitions/theme_steps.rb +19 -0
- data/features/support/env.rb +38 -0
- data/features/support/theme/theme.yml +5 -0
- data/features/theme_assets.feature +22 -0
- data/generators/repository/index.yml +3 -0
- data/generators/site/Gemfile +3 -0
- data/generators/site/config.ru +7 -0
- data/generators/theme/assets/style.css +1 -0
- data/generators/theme/layouts/default.nou.html +23 -0
- data/generators/theme/templates/default.nou.html +12 -0
- data/generators/theme/theme.yml +5 -0
- data/lib/noumenon/cli.rb +27 -0
- data/lib/noumenon/core.rb +70 -77
- data/lib/noumenon/repository/file_system.rb +102 -0
- data/lib/noumenon/repository.rb +39 -0
- data/lib/noumenon/spec/example_app.rb +19 -6
- data/lib/noumenon/spec/theme_helpers.rb +66 -0
- data/lib/noumenon/spec.rb +4 -7
- data/lib/noumenon/string_extensions.rb +21 -0
- data/lib/noumenon/template.rb +113 -72
- data/lib/noumenon/theme/assets_middleware.rb +21 -0
- data/lib/noumenon/theme.rb +106 -0
- data/lib/noumenon/version.rb +3 -1
- data/lib/noumenon.rb +68 -100
- data/noumenon.gemspec +13 -9
- data/spec/noumenon/repository/file_system_spec.rb +115 -0
- data/spec/noumenon/repository_spec.rb +40 -0
- data/spec/noumenon/template_spec.rb +9 -7
- data/spec/noumenon/theme_spec.rb +129 -0
- data/spec/noumenon_spec.rb +24 -80
- data/spec/spec_helper.rb +5 -14
- data/spec/support/file_matchers.rb +45 -0
- data/spec/support/templates/basic_template.html +1 -0
- data/spec/{fixtures/themes/example_without_layout → support}/templates/template_with_fields.html +1 -1
- metadata +143 -62
- data/lib/noumenon/configuration.rb +0 -28
- data/lib/noumenon/spec/fixtures.rb +0 -34
- data/spec/fixtures/fixture_specs/test +0 -1
- data/spec/fixtures/missing_application/mounted_app/config.yml +0 -1
- data/spec/fixtures/static_example/directory_with_index/index.yml +0 -1
- data/spec/fixtures/static_example/found.html +0 -1
- data/spec/fixtures/static_example/liquid_example.html +0 -1
- data/spec/fixtures/static_example/mounted_app/config.yml +0 -1
- data/spec/fixtures/static_example/template_with_substitutions.html +0 -1
- data/spec/fixtures/static_example/templates/basic_example.yml +0 -1
- data/spec/fixtures/static_example/templates/with_fields.yml +0 -2
- data/spec/fixtures/themes/example/assets/example.txt +0 -1
- data/spec/fixtures/themes/example/templates/layout.html +0 -3
- data/spec/fixtures/themes/example_without_layout/templates/basic_template.html +0 -1
- data/spec/fixtures/themes/example_without_layout/templates/fields.html +0 -1
- data/spec/fixtures/themes/external_theme/assets/example.txt +0 -1
- data/spec/fixtures/themes/unregistered/lib/unregistered.rb +0 -1
- data/spec/noumenon/config_spec.rb +0 -29
- data/spec/noumenon/core_spec.rb +0 -105
- data/spec/noumenon/spec/example_app_spec.rb +0 -14
- data/spec/noumenon/spec/fixtures_spec.rb +0 -41
- data/spec/noumenon/spec_spec.rb +0 -7
- data/watchr.rb +0 -2
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/.yardopts
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# Noumenon
|
2
2
|
|
3
|
-
|
3
|
+
I did have a description of where the name Noumenon came from here, but it doesn't actually fit that well. Maybe I'll
|
4
|
+
come up with a better reason for th name choice some day.
|
4
5
|
|
5
6
|
## What is This Thing?
|
6
7
|
|
@@ -11,54 +12,30 @@ populate of a content management system using the tools they are most comfortabl
|
|
11
12
|
In the case of developers (and some designers) that's version control and text editors, while in the case of content
|
12
13
|
editors thats more likely to be a web interface.
|
13
14
|
|
14
|
-
##
|
15
|
-
|
16
|
-
A Noumenon site has two fundamental components, a content repository, and a theme.
|
17
|
-
|
18
|
-
### The Content Repository
|
19
|
-
|
20
|
-
The content repository is used to store items of content for the site. By default they're represented by YAML files
|
21
|
-
in a directory tree which should match the URL structure you want to use:
|
15
|
+
## Getting Started
|
22
16
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
- /people.yml
|
28
|
-
- /company.yml
|
29
|
-
- /contact
|
30
|
-
- /config.yml
|
17
|
+
If you want to skip the theory, and just play around with things in practice then your best bet is to run `noumenon site example_site`
|
18
|
+
from a terminal, which will generate you a Gemfile, config.ru, content repository, and theme. If you want to run it
|
19
|
+
any Rack based application server should work. I've tested under Thin and Unicorn, and Heroku will work if you want
|
20
|
+
to publish a static site.
|
31
21
|
|
32
|
-
|
33
|
-
http://example.org/about/people will render /about/people.yml
|
34
|
-
|
35
|
-
Each item of content has this format:
|
36
|
-
|
37
|
-
template "page"
|
38
|
-
title: "People"
|
39
|
-
subtitle: "Our people are what makes us special"
|
40
|
-
body:
|
41
|
-
Here at Enormicorp we believe our people make us a great company.
|
42
|
-
|
43
|
-
Or at least the ones who's title starts with C and ends in O. Everyone else is just a cog really.
|
44
|
-
|
45
|
-
When requested a template with a matching name will be loaded from the current theme, and rendered with the fields
|
46
|
-
defined in the content item.
|
22
|
+
## How it Works
|
47
23
|
|
24
|
+
Noumenon splits your site into three parts:
|
48
25
|
|
49
26
|
### Themes
|
50
27
|
|
51
|
-
Themes define how your content should be presented, and can provide templates and assets.
|
52
|
-
|
53
|
-
|
54
|
-
For an example, take a look at http://github.com/Noumenon/example_theme
|
28
|
+
Themes define how your content should be presented, and can provide templates and assets. You can load a theme from any
|
29
|
+
filesystem path in your config.ru file. In the near future Ruby Gem based themes will also be supported.
|
55
30
|
|
56
31
|
#### Assets
|
57
32
|
|
58
33
|
Assets such as images, stylesheets, and javascripts are placed in the "assets" directory, and are accessible from your
|
59
|
-
application at http://example.org/themes/
|
34
|
+
application at http://example.org/themes/Theme Name/asset.png. The URL structure directly matches the directory structure
|
60
35
|
of your assets directory.
|
61
36
|
|
37
|
+
In the future some asset types will be served from the content repository instead, such as images embedded within a page.
|
38
|
+
|
62
39
|
#### Templates
|
63
40
|
|
64
41
|
The core of a theme is the templates it provides. Each template can list the fields that it supports, and mark some or all
|
@@ -92,38 +69,10 @@ If not specified the type defaults to "string", the label to a capitalised versi
|
|
92
69
|
|
93
70
|
Any fields provided to a template which aren't specified will still be available in the Liquid template part.
|
94
71
|
|
95
|
-
### Custom URL handlers
|
96
|
-
|
97
|
-
If part of your site requires something other then rendering a piece of content within a static template then you can use a
|
98
|
-
custom URL handler to provide that part of the site. In this example we'll provide a basic contact form.
|
99
|
-
|
100
|
-
#### Specifying the handler
|
101
|
-
|
102
|
-
Within your content repository create a directory with the same name as the URL you want to mount the application at, and add
|
103
|
-
a file called "config.yml" with the following content:
|
104
|
-
|
105
|
-
application: "Noumenon::Applications::ContactForm"
|
106
|
-
|
107
|
-
This specifies that instead of using the core Noumenon application you want to use the ContactForm application, an example implementation
|
108
|
-
is shown below - usually the application would be provided by a Rubygem or other source, and referenced in your Gemfile.
|
109
|
-
|
110
|
-
#### The ContactForm Handler
|
111
|
-
|
112
|
-
class Noumenon::Applications::ContactForm < Noumenon::Core
|
113
|
-
get '/' do
|
114
|
-
render_template "templates/contact/form.html"
|
115
|
-
end
|
116
|
-
|
117
|
-
post '/send' do
|
118
|
-
require 'pony'
|
119
|
-
Pony.send :to => "contact@example.org", :body => params[:body], :from => params[:from]
|
120
|
-
|
121
|
-
render_template "templates/contact/thanks.html", "body" => params[:body], "from" => params[:from]
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
72
|
#### Layouts
|
126
73
|
|
74
|
+
*WARNING:* This isn't implemented in the current version.
|
75
|
+
|
127
76
|
Layouts are used to wrap a piece of content with the overall look and feel of your website, and are provided with a single field
|
128
77
|
"body" containing the rendered content. Currently only one layout per theme is supported, and it should be called "layout.html".
|
129
78
|
|
@@ -155,27 +104,53 @@ Layouts are used to wrap a piece of content with the overall look and feel of yo
|
|
155
104
|
</body>
|
156
105
|
</html>
|
157
106
|
|
158
|
-
|
107
|
+
### A Content Repository
|
108
|
+
|
109
|
+
The site's content is stored within a repository. Each piece of content is represented by a set of key/value pairs, something
|
110
|
+
like this:
|
159
111
|
|
160
|
-
|
161
|
-
|
112
|
+
template: team_member
|
113
|
+
name: Jon Wood
|
114
|
+
position: Head Honcho of Awesomeness
|
115
|
+
description: Do you need a description after a position like that?
|
162
116
|
|
163
|
-
|
164
|
-
|
117
|
+
Currently the only available content repository uses YAML files to store your content, but shortly a MongoDB one will be created,
|
118
|
+
and the API for content repositories is simple enough that just about any datastore could be used if you want to implement an
|
119
|
+
adapater for it.
|
165
120
|
|
166
|
-
###
|
121
|
+
### Applications
|
167
122
|
|
168
|
-
If
|
123
|
+
If part of your site requires something other then rendering a piece of content within a static template then you can use a
|
124
|
+
custom URL handler to provide that part of the site. In this example we'll provide a basic contact form.
|
169
125
|
|
170
|
-
|
171
|
-
require 'noumenon'
|
126
|
+
#### The ContactForm Handler
|
172
127
|
|
173
|
-
Noumenon
|
174
|
-
|
175
|
-
|
128
|
+
class Noumenon::Applications::ContactForm < Noumenon::Core
|
129
|
+
def initialize(options = {})
|
130
|
+
@to = options[:to]
|
131
|
+
end
|
132
|
+
|
133
|
+
get '/' do
|
134
|
+
Noumenon.theme.template("templates/contact/form.html")
|
135
|
+
end
|
136
|
+
|
137
|
+
post '/send' do
|
138
|
+
require 'pony'
|
139
|
+
Pony.send :to => @to, :body => params[:body], :from => params[:from]
|
140
|
+
|
141
|
+
Noumenon.theme.template("templates/contact/thanks.html").render(body: params[:body], from: params[:from])
|
142
|
+
end
|
176
143
|
end
|
177
144
|
|
178
|
-
|
145
|
+
#### The Content item
|
146
|
+
|
147
|
+
To mount an application you need to put a content item in the tree where you want it, so in this example we'll put this at "/contact":
|
148
|
+
|
149
|
+
type: application
|
150
|
+
application: Noumenon::Applications::ContactForm
|
151
|
+
to: info@example.org
|
152
|
+
|
153
|
+
Make sure you've loaded the file that defines Noumenon::Applications::ContactForm.
|
179
154
|
|
180
155
|
## Getting Help and Contributing
|
181
156
|
|
@@ -185,6 +160,8 @@ on Noumenon as simple as possible. The best way to get in touch is to open an is
|
|
185
160
|
If you'd like to contribute fork this repository, and then submit a pull request when you're done. Please make sure to include some tests
|
186
161
|
so that your feature doesn't get broken in the future.
|
187
162
|
|
163
|
+
There are full API docs available at http://rubydoc.info/gems/noumenon/ which are generated whenever a new version is published.
|
164
|
+
|
188
165
|
## License
|
189
166
|
|
190
167
|
Noumenon is released under the MIT license by Blank Pad Development.
|
data/Rakefile
CHANGED
@@ -1,9 +1,20 @@
|
|
1
|
-
require '
|
2
|
-
|
1
|
+
require 'rspec/core/rake_task'
|
2
|
+
require 'cucumber/rake/task'
|
3
|
+
require 'yard'
|
4
|
+
require 'yard/rake/yardoc_task'
|
3
5
|
|
4
|
-
task :default =>
|
6
|
+
task :default => [ :spec, :cucumber ]
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
8
|
+
RSpec::Core::RakeTask.new
|
9
|
+
|
10
|
+
Cucumber::Rake::Task.new do |t|
|
11
|
+
t.cucumber_opts = %w(--format progress)
|
12
|
+
end
|
13
|
+
|
14
|
+
Cucumber::Rake::Task.new("cucumber:wip") do |t|
|
15
|
+
t.cucumber_opts = %w(--tags @wip:4 --wip)
|
16
|
+
end
|
17
|
+
|
18
|
+
YARD::Rake::YardocTask.new do |t|
|
19
|
+
t.name = :doc
|
9
20
|
end
|
data/bin/noumenon
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
Feature: Rendering dynamic templates
|
2
|
+
As a designer
|
3
|
+
I want to render a content item within a template
|
4
|
+
So that the end user can update their site
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given this template exists at "dynamic.nou.html"
|
8
|
+
"""
|
9
|
+
title:
|
10
|
+
required: true
|
11
|
+
body:
|
12
|
+
required: true
|
13
|
+
---
|
14
|
+
<h1>{{ title }}</h1>
|
15
|
+
<p>{{ body }}</p>
|
16
|
+
"""
|
17
|
+
|
18
|
+
Scenario: All fields provided
|
19
|
+
Given this content item exists at "/dynamic"
|
20
|
+
| template | dynamic |
|
21
|
+
| title | An example |
|
22
|
+
| body | Some content within the template. |
|
23
|
+
When I view "/dynamic"
|
24
|
+
Then the page should load
|
25
|
+
And the headline should be "An example"
|
26
|
+
And the body text should be "Some content within the template."
|
27
|
+
|
28
|
+
Scenario: Some fields are missing
|
29
|
+
Given this content item exists at "/dynamic"
|
30
|
+
| template | dynamic |
|
31
|
+
| title | An example |
|
32
|
+
When I view "/dynamic"
|
33
|
+
Then the page should return a 500 error
|
34
|
+
And the headline should be "Missing Fields"
|
35
|
+
And the body text should be "The following fields were missing from your content: body"
|
36
|
+
|
37
|
+
Scenario: Rendering within the default layout
|
38
|
+
Given this layout exists at "default.nou.html"
|
39
|
+
"""
|
40
|
+
<!doctype html>
|
41
|
+
<html>
|
42
|
+
<head>
|
43
|
+
<title>{{ title }}</title>
|
44
|
+
</head>
|
45
|
+
|
46
|
+
<body>
|
47
|
+
<header>
|
48
|
+
<h1>A Site</h1>
|
49
|
+
</header>
|
50
|
+
|
51
|
+
<section id="content">
|
52
|
+
{{ content }}
|
53
|
+
</section>
|
54
|
+
</body>
|
55
|
+
</html>
|
56
|
+
"""
|
57
|
+
And this content item exists at "/layout"
|
58
|
+
| template | dynamic |
|
59
|
+
| title | Hello, world! |
|
60
|
+
| body | Good morning world. |
|
61
|
+
When I view "/layout"
|
62
|
+
Then the page should load
|
63
|
+
And the page title should be "Hello, world!"
|
64
|
+
And the page header should be "A Site"
|
65
|
+
And the body text should be "Good morning world."
|
66
|
+
|
67
|
+
Scenario: Rendering with a non-default layout
|
68
|
+
Given this layout exists at "non_default_layout.nou.html"
|
69
|
+
"""
|
70
|
+
<!doctype html>
|
71
|
+
<html>
|
72
|
+
<head>
|
73
|
+
<title>{{ title }}</title>
|
74
|
+
</head>
|
75
|
+
|
76
|
+
<body>
|
77
|
+
<header>
|
78
|
+
<h1>A Site</h1>
|
79
|
+
</header>
|
80
|
+
|
81
|
+
<section id="content">
|
82
|
+
{{ content }}
|
83
|
+
</section>
|
84
|
+
</body>
|
85
|
+
</html>
|
86
|
+
"""
|
87
|
+
And this content item exists at "/layout"
|
88
|
+
| template | dynamic |
|
89
|
+
| layout | non_default_layout |
|
90
|
+
| title | Hello, world! |
|
91
|
+
| body | Good morning world. |
|
92
|
+
When I view "/layout"
|
93
|
+
Then the page should load
|
94
|
+
And the page title should be "Hello, world!"
|
95
|
+
And the page header should be "A Site"
|
96
|
+
And the body text should be "Good morning world."
|
97
|
+
|
98
|
+
Scenario: Rendering with a missing non-default layout
|
99
|
+
Given no layout exists at "non_default_layout.nou.html"
|
100
|
+
And this content item exists at "/layout"
|
101
|
+
| template | dynamic |
|
102
|
+
| layout | non_default_layout |
|
103
|
+
| title | Hello, world! |
|
104
|
+
| body | Good morning world. |
|
105
|
+
When I view "/layout"
|
106
|
+
Then the page should return a 500 error
|
107
|
+
And the body text should be "The layout 'non_default_layout' does not exist within the current theme."
|
@@ -0,0 +1,25 @@
|
|
1
|
+
Feature: Generating a Noumenon site
|
2
|
+
As a user
|
3
|
+
I want to generate a basic site
|
4
|
+
So that I don't I have to repeat the same steps everytime
|
5
|
+
|
6
|
+
Scenario: No arguments
|
7
|
+
When I run `bundle exec ../../bin/noumenon`
|
8
|
+
Then the output should match /Noumenon ([\d]+\.[\d]+\.[\d]+)/
|
9
|
+
And the output should contain "Tasks:"
|
10
|
+
And the output should contain "noumenon help [TASK]"
|
11
|
+
And the output should contain "noumenon site PATH"
|
12
|
+
|
13
|
+
Scenario: Site generator specified, but no path
|
14
|
+
When I run `bundle exec ../../bin/noumenon site`
|
15
|
+
Then the output should contain:
|
16
|
+
"""
|
17
|
+
"site" was called incorrectly. Call as "noumenon site PATH".
|
18
|
+
"""
|
19
|
+
|
20
|
+
Scenario: Site generator specified with a path
|
21
|
+
When I run `bundle exec ../../bin/noumenon site example_site`
|
22
|
+
Then a directory named "example_site" should exist
|
23
|
+
And the directory "example_site" should contain a Noumenon site
|
24
|
+
And the directory "example_site/theme" should contain a theme
|
25
|
+
And the directory "example_site/content" should contain a repository
|
@@ -0,0 +1,30 @@
|
|
1
|
+
Feature: Mounted Applications
|
2
|
+
As a developer
|
3
|
+
I want to mount an application at /app
|
4
|
+
So that I can provide extra functionality
|
5
|
+
In order to deliver the site my client wants
|
6
|
+
|
7
|
+
Scenario: An application has been mounted
|
8
|
+
Given this content item exists at "/app"
|
9
|
+
| type | application |
|
10
|
+
| application | Noumenon::Spec::ExampleApp |
|
11
|
+
When I view "/app"
|
12
|
+
Then the page should load
|
13
|
+
And the headline should be "This is a mounted application"
|
14
|
+
|
15
|
+
Scenario: Loading paths below the mounted application
|
16
|
+
Given this content item exists at "/app"
|
17
|
+
| type | application |
|
18
|
+
| application | Noumenon::Spec::ExampleApp |
|
19
|
+
When I view "/app/sub"
|
20
|
+
Then the page should load
|
21
|
+
And the headline should be "This is a sub-page"
|
22
|
+
|
23
|
+
Scenario: Passing configuration to an application
|
24
|
+
Given this content item exists at "/app"
|
25
|
+
| type | application |
|
26
|
+
| application | Noumenon::Spec::ExampleApp |
|
27
|
+
| message | Hello, world! |
|
28
|
+
When I view "/app"
|
29
|
+
Then the page should load
|
30
|
+
And the headline should be "Hello, world!"
|
@@ -0,0 +1,43 @@
|
|
1
|
+
Feature: Rendering a static template
|
2
|
+
In order to display a non-dynamic page
|
3
|
+
As a designer
|
4
|
+
I want to render a static template
|
5
|
+
|
6
|
+
Scenario: Template exists
|
7
|
+
Given this template exists at "static.nou.html"
|
8
|
+
"""
|
9
|
+
<h1>Static Template</h1>
|
10
|
+
<p>This is a static template which does not have any fields.</p>
|
11
|
+
"""
|
12
|
+
And this content item exists at "/static"
|
13
|
+
| template | static |
|
14
|
+
When I view "/static"
|
15
|
+
Then the page should load
|
16
|
+
And the headline should be "Static Template"
|
17
|
+
And the body text should be "This is a static template which does not have any fields."
|
18
|
+
|
19
|
+
Scenario: Template does not exist
|
20
|
+
Given no template exists at "static.nou.html"
|
21
|
+
And this content item exists at "/static"
|
22
|
+
| template | static |
|
23
|
+
When I view "/static"
|
24
|
+
Then the page should return a 500 error
|
25
|
+
And the headline should be "Missing Template"
|
26
|
+
And the body text should be "The template 'static' does not exist within the current theme."
|
27
|
+
|
28
|
+
Scenario: Template is not specified
|
29
|
+
Given this template exists at "default.nou.html"
|
30
|
+
"""
|
31
|
+
<h1>Default Template</h1>
|
32
|
+
"""
|
33
|
+
And this content item exists at "/default"
|
34
|
+
| key | value |
|
35
|
+
When I view "/default"
|
36
|
+
Then the page should load
|
37
|
+
And the headline should be "Default Template"
|
38
|
+
|
39
|
+
Scenario: Content item does not exist
|
40
|
+
Given no content item exists at "/static"
|
41
|
+
When I view "/static"
|
42
|
+
Then the page should return a 404 error
|
43
|
+
And the headline should be "Page Not Found"
|
@@ -0,0 +1,7 @@
|
|
1
|
+
Given /^the asset "([^"]*)" does not exist within the theme$/ do |asset_name|
|
2
|
+
# noop
|
3
|
+
end
|
4
|
+
|
5
|
+
Given /^the asset "([^"]*)" exists within the theme with this content:$/ do |asset_name, content|
|
6
|
+
File.open(File.join(Noumenon.theme.path, "assets", asset_name), "w") { |f| f.print content }
|
7
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
def generator_file(generator, file)
|
2
|
+
File.read File.expand_path("../../../generators/#{generator}/#{file}", __FILE__)
|
3
|
+
end
|
4
|
+
|
5
|
+
Then /^the directory "([^"]*)" should contain a Noumenon site$/ do |path|
|
6
|
+
Then %Q{a file named "#{path}/Gemfile" should exist}
|
7
|
+
And %Q{a file named "#{path}/config.ru" should exist}
|
8
|
+
|
9
|
+
check_exact_file_content "#{path}/Gemfile", generator_file("site", "Gemfile")
|
10
|
+
check_exact_file_content "#{path}/config.ru", generator_file("site", "config.ru")
|
11
|
+
end
|
12
|
+
|
13
|
+
Then /^the directory "([^"]*)" should contain a theme$/ do |path|
|
14
|
+
check_exact_file_content "#{path}/theme.yml", generator_file("theme", "theme.yml")
|
15
|
+
check_exact_file_content "#{path}/layouts/default.nou.html", generator_file("theme", "layouts/default.nou.html")
|
16
|
+
check_exact_file_content "#{path}/templates/default.nou.html", generator_file("theme", "templates/default.nou.html")
|
17
|
+
check_exact_file_content "#{path}/assets/style.css", generator_file("theme", "assets/style.css")
|
18
|
+
end
|
19
|
+
|
20
|
+
Then /^the directory "([^"]*)" should contain a repository$/ do |path|
|
21
|
+
check_exact_file_content "#{path}/index.yml", generator_file("repository", "index.yml")
|
22
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
When /^I view "([^"]*)"$/ do |path|
|
2
|
+
visit path
|
3
|
+
end
|
4
|
+
|
5
|
+
Then /^the page should load$/ do
|
6
|
+
page.status_code.should == 200
|
7
|
+
end
|
8
|
+
|
9
|
+
Then /^the page should return a (\d+) error$/ do |status|
|
10
|
+
page.status_code.should == status.to_i
|
11
|
+
end
|
12
|
+
|
13
|
+
Then /^the page content should be:$/ do |content|
|
14
|
+
page.source.should == content
|
15
|
+
end
|
16
|
+
|
17
|
+
Then /^the headline should be "([^"]*)"$/ do |headline|
|
18
|
+
page.should have_css "h1", :text => headline
|
19
|
+
end
|
20
|
+
|
21
|
+
Then /^the body text should be "([^"]*)"$/ do |body|
|
22
|
+
page.should have_css "p", :text => body
|
23
|
+
end
|
24
|
+
|
25
|
+
Then /^the page title should be "([^"]*)"$/ do |title|
|
26
|
+
page.should have_css "head title", :text => title
|
27
|
+
end
|
28
|
+
|
29
|
+
Then /^the page header should be "([^"]*)"$/ do |header|
|
30
|
+
page.should have_css "header h1", :text => header
|
31
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Given /^this template exists at "([^"]*)"$/ do |path, template|
|
2
|
+
File.open(File.join(Noumenon.theme.path, "templates", path), "w") do |f|
|
3
|
+
f.write(template)
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
Given /^no template exists at "([^"]*)"$/ do |path|
|
8
|
+
# noop
|
9
|
+
end
|
10
|
+
|
11
|
+
Given /^this layout exists at "([^"]*)"$/ do |path, template|
|
12
|
+
File.open(File.join(Noumenon.theme.path, "layouts", path), "w") do |f|
|
13
|
+
f.write(template)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Given /^no layout exists at "([^"]*)"$/ do |arg1|
|
18
|
+
# noop
|
19
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Generated by cucumber-sinatra. (2011-05-20 13:59:19 +0100)
|
2
|
+
|
3
|
+
ENV['RACK_ENV'] = 'test'
|
4
|
+
|
5
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'lib/noumenon.rb')
|
6
|
+
|
7
|
+
require 'aruba/cucumber'
|
8
|
+
require 'capybara/cucumber'
|
9
|
+
require 'rspec'
|
10
|
+
|
11
|
+
require 'fileutils'
|
12
|
+
|
13
|
+
include Noumenon::Spec::ThemeHelpers
|
14
|
+
|
15
|
+
Capybara.app = Noumenon.server
|
16
|
+
|
17
|
+
World do
|
18
|
+
include RSpec::Expectations
|
19
|
+
include RSpec::Matchers
|
20
|
+
|
21
|
+
def content_path
|
22
|
+
File.expand_path('../tmp/content', __FILE__)
|
23
|
+
end
|
24
|
+
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
Before do
|
29
|
+
Noumenon.theme = create_theme(name: "Example Theme")
|
30
|
+
|
31
|
+
FileUtils.mkdir_p content_path
|
32
|
+
Noumenon.content_repository = Noumenon::Repository::FileSystem.new(path: content_path)
|
33
|
+
end
|
34
|
+
|
35
|
+
After do
|
36
|
+
FileUtils.rm_r content_path
|
37
|
+
FileUtils.rm_r theme_path
|
38
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
Feature: Theme Assets
|
2
|
+
As a designer
|
3
|
+
I want to serve files from my theme
|
4
|
+
So that I can bundle any required images with it
|
5
|
+
In order to make using themes simpler
|
6
|
+
|
7
|
+
Scenario: The asset does not exist
|
8
|
+
Given the asset "foo.txt" does not exist within the theme
|
9
|
+
When I view "/themes/Example%20Theme/foo.txt"
|
10
|
+
Then the page should return a 404 error
|
11
|
+
|
12
|
+
Scenario: The asset does exist
|
13
|
+
Given the asset "foo.txt" exists within the theme with this content:
|
14
|
+
"""
|
15
|
+
Hello, world!
|
16
|
+
"""
|
17
|
+
When I view "/themes/Example%20Theme/foo.txt"
|
18
|
+
Then the page should load
|
19
|
+
And the page content should be:
|
20
|
+
"""
|
21
|
+
Hello, world!
|
22
|
+
"""
|
@@ -0,0 +1 @@
|
|
1
|
+
/* Your themes styles should go here. */
|