noumenon 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/.gitignore +3 -0
  2. data/.travis.yml +0 -4
  3. data/.yardopts +5 -0
  4. data/Gemfile +1 -3
  5. data/README.md +57 -80
  6. data/Rakefile +17 -6
  7. data/bin/noumenon +6 -0
  8. data/features/dynamic_template_rendering.feature +107 -0
  9. data/features/generator/site_generator.feature +25 -0
  10. data/features/mounted_applications.feature +30 -0
  11. data/features/static_template_rendering.feature +43 -0
  12. data/features/step_definitions/asset_steps.rb +7 -0
  13. data/features/step_definitions/content_steps.rb +7 -0
  14. data/features/step_definitions/generator_steps.rb +22 -0
  15. data/features/step_definitions/request_steps.rb +31 -0
  16. data/features/step_definitions/theme_steps.rb +19 -0
  17. data/features/support/env.rb +38 -0
  18. data/features/support/theme/theme.yml +5 -0
  19. data/features/theme_assets.feature +22 -0
  20. data/generators/repository/index.yml +3 -0
  21. data/generators/site/Gemfile +3 -0
  22. data/generators/site/config.ru +7 -0
  23. data/generators/theme/assets/style.css +1 -0
  24. data/generators/theme/layouts/default.nou.html +23 -0
  25. data/generators/theme/templates/default.nou.html +12 -0
  26. data/generators/theme/theme.yml +5 -0
  27. data/lib/noumenon/cli.rb +27 -0
  28. data/lib/noumenon/core.rb +70 -77
  29. data/lib/noumenon/repository/file_system.rb +102 -0
  30. data/lib/noumenon/repository.rb +39 -0
  31. data/lib/noumenon/spec/example_app.rb +19 -6
  32. data/lib/noumenon/spec/theme_helpers.rb +66 -0
  33. data/lib/noumenon/spec.rb +4 -7
  34. data/lib/noumenon/string_extensions.rb +21 -0
  35. data/lib/noumenon/template.rb +113 -72
  36. data/lib/noumenon/theme/assets_middleware.rb +21 -0
  37. data/lib/noumenon/theme.rb +106 -0
  38. data/lib/noumenon/version.rb +3 -1
  39. data/lib/noumenon.rb +68 -100
  40. data/noumenon.gemspec +13 -9
  41. data/spec/noumenon/repository/file_system_spec.rb +115 -0
  42. data/spec/noumenon/repository_spec.rb +40 -0
  43. data/spec/noumenon/template_spec.rb +9 -7
  44. data/spec/noumenon/theme_spec.rb +129 -0
  45. data/spec/noumenon_spec.rb +24 -80
  46. data/spec/spec_helper.rb +5 -14
  47. data/spec/support/file_matchers.rb +45 -0
  48. data/spec/support/templates/basic_template.html +1 -0
  49. data/spec/{fixtures/themes/example_without_layout → support}/templates/template_with_fields.html +1 -1
  50. metadata +143 -62
  51. data/lib/noumenon/configuration.rb +0 -28
  52. data/lib/noumenon/spec/fixtures.rb +0 -34
  53. data/spec/fixtures/fixture_specs/test +0 -1
  54. data/spec/fixtures/missing_application/mounted_app/config.yml +0 -1
  55. data/spec/fixtures/static_example/directory_with_index/index.yml +0 -1
  56. data/spec/fixtures/static_example/found.html +0 -1
  57. data/spec/fixtures/static_example/liquid_example.html +0 -1
  58. data/spec/fixtures/static_example/mounted_app/config.yml +0 -1
  59. data/spec/fixtures/static_example/template_with_substitutions.html +0 -1
  60. data/spec/fixtures/static_example/templates/basic_example.yml +0 -1
  61. data/spec/fixtures/static_example/templates/with_fields.yml +0 -2
  62. data/spec/fixtures/themes/example/assets/example.txt +0 -1
  63. data/spec/fixtures/themes/example/templates/layout.html +0 -3
  64. data/spec/fixtures/themes/example_without_layout/templates/basic_template.html +0 -1
  65. data/spec/fixtures/themes/example_without_layout/templates/fields.html +0 -1
  66. data/spec/fixtures/themes/external_theme/assets/example.txt +0 -1
  67. data/spec/fixtures/themes/unregistered/lib/unregistered.rb +0 -1
  68. data/spec/noumenon/config_spec.rb +0 -29
  69. data/spec/noumenon/core_spec.rb +0 -105
  70. data/spec/noumenon/spec/example_app_spec.rb +0 -14
  71. data/spec/noumenon/spec/fixtures_spec.rb +0 -41
  72. data/spec/noumenon/spec_spec.rb +0 -7
  73. data/watchr.rb +0 -2
data/.gitignore CHANGED
@@ -2,3 +2,6 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ .yardoc
6
+ doc
7
+ tmp
data/.travis.yml CHANGED
@@ -1,6 +1,2 @@
1
1
  rvm:
2
- - 1.8.7
3
2
  - 1.9.2
4
- - ree
5
- - rbx
6
- - jruby
data/.yardopts ADDED
@@ -0,0 +1,5 @@
1
+ --query @api.text == "public"
2
+ --title "Noumenon"
3
+ lib/**/*.rb
4
+ lib/*.rb -
5
+ README.md MIT-LICENSE
data/Gemfile CHANGED
@@ -1,4 +1,2 @@
1
- source "http://rubygems.org"
2
-
3
- # Specify your gem's dependencies in noumenon.gemspec
1
+ source :rubygems
4
2
  gemspec
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Noumenon
2
2
 
3
- Noumenon: Noun. The intellectual conception of a thing as it is in itself, not as it is known through perception.
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
- ## How it Works
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
- - index.yml
25
- - /about
26
- - /index.yml
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
- In the example above visiting http://example.org/ will render the content in /index.yml, while visiting
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. A theme will usually come
52
- in the form of a Rubygem, either published to rubygems.org, or from some other source which Bundler can access.
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/theme_name/asset.png. The URL structure directly matches the directory structure
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
- ## Publishing Your Site
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
- Currently the quickest way to get a Noumenon site on the internet is using Heroku. See http://github.com/Noumenon/example_site for
161
- an example of how to get that working.
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
- Note that once the admin backend is in place, Heroku may not be supported, and certainly won't be supported when using a filesystem
164
- based backend for your content repository.
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
- ### Example config.ru
121
+ ### Applications
167
122
 
168
- If you want to host on your own hardware use a config.ru like this:
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
- require 'bundler/setup'
171
- require 'noumenon'
126
+ #### The ContactForm Handler
172
127
 
173
- Noumenon.config do |c|
174
- c.content_repository_path = "/path/to/content_repository"
175
- c.theme = "noumenon-example_theme" # Requires you to have a reference to noumenon-example_theme in your Gemfile.
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
- run Noumenon.boot
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 'bundler'
2
- Bundler::GemHelper.install_tasks
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 => "specs"
6
+ task :default => [ :spec, :cucumber ]
5
7
 
6
- desc "Run all specs"
7
- task "specs" do
8
- exec "rspec spec"
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,6 @@
1
+ #!/usr/bin/env ruby
2
+ require 'noumenon/cli'
3
+ require 'noumenon/version'
4
+
5
+ puts "Noumenon #{Noumenon::VERSION}\n\n"
6
+ Noumenon::Cli.start
@@ -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,7 @@
1
+ Given /^this content item exists at "([^"]*)"$/ do |path, fields|
2
+ Noumenon.content_repository.put(path, fields.rows_hash)
3
+ end
4
+
5
+ Given /^no content item exists at "([^"]*)"$/ do |path|
6
+ # noop
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,5 @@
1
+ name: Cucumber Features Theme
2
+ author: Jon Wood
3
+ email: jon@blankpad.net
4
+ copyright: 2011, Blank Pad Development
5
+ license: MIT
@@ -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,3 @@
1
+ template: "default"
2
+ title: "Welcome to Noumenon"
3
+ body: "You've just created a Noumenon site, well done!"
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gem "noumenon"
@@ -0,0 +1,7 @@
1
+ require 'bundler/setup'
2
+ require 'noumenon'
3
+
4
+ Noumenon.theme = Noumenon::Theme.load("./theme")
5
+ Noumenon.content_repository = Noumenon::Repository::FileSystem.new(path: "./content")
6
+
7
+ run Noumenon.server
@@ -0,0 +1 @@
1
+ /* Your themes styles should go here. */