noumenon 0.1.7 → 0.2.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.
- data/CHANGELOG.md +19 -0
- data/README.md +7 -4
- data/features/asset_serving/{from_content_repositories.feature → from_a_repository.feature} +2 -14
- data/features/step_definitions/asset_steps.rb +2 -2
- data/features/step_definitions/generator_steps.rb +3 -1
- data/features/support/env.rb +8 -3
- data/generators/repository/assets/.gitkeep +0 -0
- data/generators/repository/{index.yml → pages/index.yml} +0 -0
- data/generators/site/config.ru +2 -2
- data/generators/theme/layouts/default.nou.html +1 -1
- data/lib/noumenon.rb +2 -1
- data/lib/noumenon/asset_repository.rb +49 -0
- data/lib/noumenon/asset_repository/file_system.rb +64 -0
- data/lib/noumenon/{repository.rb → content_repository.rb} +2 -2
- data/lib/noumenon/{repository → content_repository}/file_system.rb +9 -4
- data/lib/noumenon/core.rb +13 -2
- data/lib/noumenon/spec/theme_helpers.rb +1 -1
- data/lib/noumenon/template/core_tags.rb +1 -1
- data/lib/noumenon/version.rb +1 -1
- data/spec/noumenon/asset_repository/file_system_spec.rb +63 -0
- data/spec/noumenon/asset_repository_spec.rb +16 -0
- data/spec/noumenon/{repository → content_repository}/file_system_spec.rb +5 -37
- data/spec/noumenon/{repository_spec.rb → content_repository_spec.rb} +2 -9
- data/spec/noumenon_spec.rb +5 -5
- metadata +18 -11
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
# 0.2.0
|
2
|
+
|
3
|
+
## Backwards Compatiability Broken
|
4
|
+
|
5
|
+
This version is incompatiable with the 0.1 series due to content and asset repositories being split.
|
6
|
+
|
7
|
+
## New Features
|
8
|
+
|
9
|
+
* Content and asset repositories are now two different things, largely to avoid special casing the assets
|
10
|
+
directory for file system repositories, but it should also allow more flexibility going forward.
|
11
|
+
|
12
|
+
## Bug Fixes
|
13
|
+
|
14
|
+
* Use send_file to serve assets from the content repository so that the correct metadata is provided
|
15
|
+
to allow it to be loaded in a browser.
|
16
|
+
|
17
|
+
* Use the {% theme_asset %} tag in generated themes to load the stylesheet so that changing the theme name
|
18
|
+
doesn't break the link.
|
19
|
+
|
1
20
|
# 0.1.7
|
2
21
|
|
3
22
|
## New Features
|
data/README.md
CHANGED
@@ -42,8 +42,6 @@ Assets such as images, stylesheets, and javascripts are placed in the "assets" d
|
|
42
42
|
application at http://example.org/themes/Theme Name/asset.png. The URL structure directly matches the directory structure
|
43
43
|
of your assets directory.
|
44
44
|
|
45
|
-
In the future some asset types will be served from the content repository instead, such as images embedded within a page.
|
46
|
-
|
47
45
|
#### Templates
|
48
46
|
|
49
47
|
The core of a theme is the templates it provides. Each template can list the fields that it supports, and mark some or all
|
@@ -130,8 +128,13 @@ Currently the only available content repository uses YAML files to store your co
|
|
130
128
|
and the API for content repositories is simple enough that just about any datastore could be used if you want to implement an
|
131
129
|
adapater for it.
|
132
130
|
|
133
|
-
|
134
|
-
|
131
|
+
### An Asset Repository
|
132
|
+
|
133
|
+
The asset repository is used to store arbitrary files, such as images to embed within pages.
|
134
|
+
|
135
|
+
Any uploaded assets can usually be accessed from /assets/path/to/image.jpg, although in some cases it may be quicker to access them
|
136
|
+
directly. To get the correct URL for an asset use the `{% asset /path/to/image.jpg %}` template tag, which will return the correct
|
137
|
+
URL.
|
135
138
|
|
136
139
|
### Applications
|
137
140
|
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Feature: Serving assets from the
|
1
|
+
Feature: Serving assets from the asset repository
|
2
2
|
As a user
|
3
|
-
I want to
|
3
|
+
I want to be able to upload assets to my site
|
4
4
|
So that I can attach my own images to pages
|
5
5
|
|
6
6
|
Scenario: The asset has been added
|
@@ -18,15 +18,3 @@ Feature: Serving assets from the content repository
|
|
18
18
|
Given there is no asset called "example.txt" in the asset repository
|
19
19
|
When I view "/assets/example.txt"
|
20
20
|
Then the page should return a 404 error
|
21
|
-
|
22
|
-
Scenario: Using an alternative asset repository
|
23
|
-
Given I have chosen to use a seperate asset repository
|
24
|
-
And I have uploaded this asset as "example.txt" to the asset repository
|
25
|
-
"""
|
26
|
-
Alternative repos FTW
|
27
|
-
"""
|
28
|
-
When I view "/assets/example.txt"
|
29
|
-
Then the page content should be:
|
30
|
-
"""
|
31
|
-
Alternative repos FTW
|
32
|
-
"""
|
@@ -8,11 +8,11 @@ end
|
|
8
8
|
|
9
9
|
Given /^I have chosen to use a seperate asset repository$/ do
|
10
10
|
FileUtils.mkdir_p File.join(tmp_path, "assets")
|
11
|
-
Noumenon.asset_repository = Noumenon::
|
11
|
+
Noumenon.asset_repository = Noumenon::ContentRepository::FileSystem.new(path: File.join(tmp_path, "assets"))
|
12
12
|
end
|
13
13
|
|
14
14
|
Given /^I have uploaded this asset as "([^"]*)" to the asset repository$/ do |path, string|
|
15
|
-
Noumenon.asset_repository.
|
15
|
+
Noumenon.asset_repository.put(path, string)
|
16
16
|
end
|
17
17
|
|
18
18
|
Given /^there is no asset called "([^"]*)" in the asset repository$/ do |path|
|
@@ -18,5 +18,7 @@ Then /^the directory "([^"]*)" should contain a theme$/ do |path|
|
|
18
18
|
end
|
19
19
|
|
20
20
|
Then /^the directory "([^"]*)" should contain a repository$/ do |path|
|
21
|
-
|
21
|
+
Then %Q{a directory named "#{path}/pages" should exist}
|
22
|
+
check_exact_file_content "#{path}/pages/index.yml", generator_file("repository/pages", "index.yml")
|
23
|
+
And %Q{a directory named "#{path}/assets" should exist}
|
22
24
|
end
|
data/features/support/env.rb
CHANGED
@@ -19,13 +19,17 @@ World do
|
|
19
19
|
include RSpec::Matchers
|
20
20
|
|
21
21
|
def tmp_path
|
22
|
-
File.expand_path('
|
22
|
+
File.expand_path('../../../tmp', __FILE__)
|
23
23
|
end
|
24
24
|
|
25
25
|
def content_path
|
26
26
|
File.join(tmp_path, "content")
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
|
+
def asset_path
|
30
|
+
File.join(tmp_path, "assets")
|
31
|
+
end
|
32
|
+
|
29
33
|
true
|
30
34
|
end
|
31
35
|
|
@@ -33,7 +37,8 @@ Before do
|
|
33
37
|
Noumenon.theme = create_theme(name: "Example Theme")
|
34
38
|
|
35
39
|
FileUtils.mkdir_p content_path
|
36
|
-
Noumenon.content_repository = Noumenon::
|
40
|
+
Noumenon.content_repository = Noumenon::ContentRepository::FileSystem.new(path: content_path)
|
41
|
+
Noumenon.asset_repository = Noumenon::AssetRepository::FileSystem.new(path: asset_path)
|
37
42
|
end
|
38
43
|
|
39
44
|
After do
|
File without changes
|
File without changes
|
data/generators/site/config.ru
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
require 'bundler/setup'
|
2
1
|
require 'noumenon'
|
3
2
|
|
4
3
|
Noumenon.theme = Noumenon::Theme.load("./theme")
|
5
|
-
Noumenon.content_repository = Noumenon::
|
4
|
+
Noumenon.content_repository = Noumenon::ContentRepository::FileSystem.new(path: "./content/pages")
|
5
|
+
Noumenon.content_repository = Noumenon::AssetRepository::FileSystem.new(path: "./content/assets")
|
6
6
|
|
7
7
|
run Noumenon.server
|
data/lib/noumenon.rb
CHANGED
@@ -5,8 +5,9 @@ require 'rack/builder'
|
|
5
5
|
|
6
6
|
# @api public
|
7
7
|
module Noumenon
|
8
|
+
autoload :AssetRepository, 'noumenon/asset_repository'
|
8
9
|
autoload :Core, 'noumenon/core'
|
9
|
-
autoload :
|
10
|
+
autoload :ContentRepository, 'noumenon/content_repository'
|
10
11
|
autoload :Template, 'noumenon/template'
|
11
12
|
autoload :Theme, 'noumenon/theme'
|
12
13
|
autoload :Spec, 'noumenon/spec'
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class Noumenon::AssetRepository
|
2
|
+
autoload :FileSystem, 'noumenon/asset_repository/file_system'
|
3
|
+
|
4
|
+
# Provides access to options set on initialization.
|
5
|
+
# @api public
|
6
|
+
attr_reader :options
|
7
|
+
|
8
|
+
# Create a new Repository instance.
|
9
|
+
#
|
10
|
+
# @param [ Hash, #each ] options A hash of options to use when configuring the repository.
|
11
|
+
# @api public
|
12
|
+
def initialize(options = {})
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
# Saves a static asset to the repository. To be saved the asset must have a file extension, to prevent
|
17
|
+
# problems with an entire directory being overridden by a single asset.
|
18
|
+
#
|
19
|
+
# @param [ String ] path The path to save the asset at.
|
20
|
+
# @param [ String ] content The contents of the asset.
|
21
|
+
# @raises [ ArgumentError ] The path did not have a file extension.
|
22
|
+
def put(path, content)
|
23
|
+
not_supported "saving assets"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Retrieves a static asset from the repository. If the asset does not exist nil is returned.
|
27
|
+
#
|
28
|
+
# @param [ String ] path The path to load from.
|
29
|
+
# @return [ String, nil ] The asset's content, or nil if it does not exist.
|
30
|
+
def get(path)
|
31
|
+
not_supported "loading assets"
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns a URL for the specified asset, without checking for it's existence.
|
35
|
+
#
|
36
|
+
# This is most useful for repositories that save their assets to a CDN such as S3, and allows them to be
|
37
|
+
# directly accessed from there, instead of downloaded and then retransmitted.
|
38
|
+
#
|
39
|
+
# @param [ String ] path The asset path within the repository.
|
40
|
+
# @return [ String ] The URL to use when requesting the asset.
|
41
|
+
def url_for(path)
|
42
|
+
File.join("/assets", path)
|
43
|
+
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
def not_supported(action)
|
47
|
+
raise NotImplementedError.new("This repository type does not support #{action}.")
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'noumenon/asset_repository'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
# A content repository which uses YAML files within the filesystem for storage.
|
5
|
+
#
|
6
|
+
# @example The structure of a filesystem repository
|
7
|
+
# index.yml
|
8
|
+
# |- about
|
9
|
+
# |- index.yml
|
10
|
+
# |- team.yml
|
11
|
+
# |- company.yml
|
12
|
+
# contact.yml
|
13
|
+
#
|
14
|
+
# @example A piece of content
|
15
|
+
# template: team_member
|
16
|
+
# name: Jon Wood
|
17
|
+
# position: Head Honcho of Awesomeness
|
18
|
+
# bio: Jon's just awesome, we'll leave it at that.
|
19
|
+
#
|
20
|
+
# @api public
|
21
|
+
class Noumenon::AssetRepository::FileSystem < Noumenon::AssetRepository
|
22
|
+
# @param [ Hash ] options A hash of options.
|
23
|
+
# @option options [ String ] :path The path to access the repository at.
|
24
|
+
# @api public
|
25
|
+
def initialize(options = {})
|
26
|
+
unless options.key? :path
|
27
|
+
raise ArgumentError.new("You must provide a path to the asset repository: Noumenon::AssetRepository::FileSystem.new(path: '/tmp')")
|
28
|
+
end
|
29
|
+
|
30
|
+
super options
|
31
|
+
end
|
32
|
+
|
33
|
+
# Save a static asset to the repository.
|
34
|
+
#
|
35
|
+
# @see Noumenon::Repository#save_asset
|
36
|
+
# @api public
|
37
|
+
def put(path, content)
|
38
|
+
raise ArgumentError.new("Assets must have a file extension.") unless File.extname(path).size > 0
|
39
|
+
|
40
|
+
full_path = filesystem_path_for(path)
|
41
|
+
directory = File.dirname(full_path)
|
42
|
+
FileUtils.mkdir_p(directory) unless File.exist?(directory)
|
43
|
+
File.open(full_path, "w") { |f| f.write content }
|
44
|
+
end
|
45
|
+
|
46
|
+
# Retreive a static asset to the repository.
|
47
|
+
#
|
48
|
+
# @see Noumenon::Repository#get_asset
|
49
|
+
# @api public
|
50
|
+
def get(path)
|
51
|
+
return nil unless File.exist?(filesystem_path_for(path))
|
52
|
+
return nil unless File.extname(path).size > 0
|
53
|
+
File.read filesystem_path_for(path)
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_asset_path(path)
|
57
|
+
return nil unless File.extname(path).size > 0
|
58
|
+
filesystem_path_for path
|
59
|
+
end
|
60
|
+
|
61
|
+
def filesystem_path_for(path)
|
62
|
+
File.join options[:path], path
|
63
|
+
end
|
64
|
+
end
|
@@ -4,8 +4,8 @@ require 'noumenon'
|
|
4
4
|
# expected API for a repository.
|
5
5
|
#
|
6
6
|
# @api public
|
7
|
-
class Noumenon::
|
8
|
-
autoload :FileSystem, 'noumenon/
|
7
|
+
class Noumenon::ContentRepository
|
8
|
+
autoload :FileSystem, 'noumenon/content_repository/file_system'
|
9
9
|
|
10
10
|
# Provides access to options set on initialization.
|
11
11
|
# @api public
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'noumenon/
|
1
|
+
require 'noumenon/content_repository'
|
2
2
|
require 'yaml'
|
3
3
|
require 'fileutils'
|
4
4
|
|
@@ -19,13 +19,13 @@ require 'fileutils'
|
|
19
19
|
# bio: Jon's just awesome, we'll leave it at that.
|
20
20
|
#
|
21
21
|
# @api public
|
22
|
-
class Noumenon::
|
22
|
+
class Noumenon::ContentRepository::FileSystem < Noumenon::ContentRepository
|
23
23
|
# @param [ Hash ] options A hash of options.
|
24
24
|
# @option options [ String ] :path The path to access the repository at.
|
25
25
|
# @api public
|
26
26
|
def initialize(options = {})
|
27
27
|
unless options.key? :path
|
28
|
-
raise ArgumentError.new("You must provide a path to the content repository: Noumenon::
|
28
|
+
raise ArgumentError.new("You must provide a path to the content repository: Noumenon::ContentRepository::FileSystem.new(path: '/tmp')")
|
29
29
|
end
|
30
30
|
|
31
31
|
super options
|
@@ -75,7 +75,7 @@ class Noumenon::Repository::FileSystem < Noumenon::Repository
|
|
75
75
|
items.reject { |i| i.gsub(root, "").split("/").size > depth + 1 }.collect do |item|
|
76
76
|
path = item == "" ? "/" : item
|
77
77
|
|
78
|
-
# Loading
|
78
|
+
# Loading every item probably isn't scalable, but it'll do for now. We can add caching
|
79
79
|
# at a later date if needed.
|
80
80
|
page = get(path).merge({ path: path })
|
81
81
|
page[:children] = children(page[:path], depth - 1) if depth - 1 > 0
|
@@ -100,6 +100,11 @@ class Noumenon::Repository::FileSystem < Noumenon::Repository
|
|
100
100
|
return nil unless File.extname(path).size > 0
|
101
101
|
read_file File.join("assets", path)
|
102
102
|
end
|
103
|
+
|
104
|
+
def get_asset_path(path)
|
105
|
+
return nil unless File.extname(path).size > 0
|
106
|
+
repository_path "assets/#{path}"
|
107
|
+
end
|
103
108
|
|
104
109
|
private
|
105
110
|
# Return the on-disk path to a repository item.
|
data/lib/noumenon/core.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'noumenon'
|
2
2
|
require 'sinatra'
|
3
|
+
require 'rack/mime'
|
3
4
|
|
4
5
|
# The core Noumenon web application, responsible for loading content from the repository,
|
5
6
|
# and then either rendering it with the appropriate template, or passing it to the specified
|
@@ -41,11 +42,21 @@ class Noumenon::Core < Sinatra::Base
|
|
41
42
|
Noumenon.content_repository
|
42
43
|
end
|
43
44
|
|
45
|
+
# The default assets handler is incredibly naive, loading the entire asset into memory, and then
|
46
|
+
# sending it back out again. In the future asset repositories will be able to implement more sensible
|
47
|
+
# methods of sending content, such as redirecting to an S3 URL.
|
48
|
+
#
|
49
|
+
# TODO: Abstract /assets/ out to a middleware which can be implemented by repositories which
|
50
|
+
# can't just provide a URL straight up (such as MongoDB).
|
44
51
|
get "/assets/*" do |path|
|
45
|
-
asset = Noumenon.asset_repository.
|
52
|
+
asset = Noumenon.asset_repository.get(path)
|
46
53
|
halt 404, "Asset not found" unless asset
|
47
54
|
|
48
|
-
|
55
|
+
status 200
|
56
|
+
headers \
|
57
|
+
"Content-Type" => Rack::Mime.mime_type(File.extname(path)),
|
58
|
+
"Length" => asset.bytesize.to_s
|
59
|
+
body asset
|
49
60
|
end
|
50
61
|
|
51
62
|
get "*" do |path|
|
@@ -11,7 +11,7 @@ module Noumenon
|
|
11
11
|
# @return [ String ]
|
12
12
|
# @api public
|
13
13
|
def theme_path
|
14
|
-
File.
|
14
|
+
File.expand_path("../../../../tmp/example_theme", __FILE__)
|
15
15
|
end
|
16
16
|
|
17
17
|
# Create a new theme directory at #theme_path.
|
data/lib/noumenon/version.rb
CHANGED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Noumenon::AssetRepository::FileSystem do
|
4
|
+
let(:assets_path) { File.join(File.dirname(__FILE__), "..", "..", "..", "..", "tmp", "assets") }
|
5
|
+
|
6
|
+
around do |example|
|
7
|
+
FileUtils.mkdir_p assets_path
|
8
|
+
example.run
|
9
|
+
FileUtils.rm_r assets_path
|
10
|
+
end
|
11
|
+
|
12
|
+
subject do
|
13
|
+
Noumenon::AssetRepository::FileSystem.new path: assets_path
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "initialization" do
|
17
|
+
context "when no path option is provided" do
|
18
|
+
it "should raise an ArgumentError" do
|
19
|
+
lambda { Noumenon::AssetRepository::FileSystem.new }.should raise_error ArgumentError
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should provide details of the error of how to resolve the error" do
|
23
|
+
begin
|
24
|
+
Noumenon::AssetRepository::FileSystem.new
|
25
|
+
rescue ArgumentError => e
|
26
|
+
e.to_s.should == "You must provide a path to the asset repository: Noumenon::AssetRepository::FileSystem.new(path: '/tmp')"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it { should implement(:put, "/foo.txt", "foo") }
|
33
|
+
describe "saving assets" do
|
34
|
+
it "raises an ArgumentError when the path has no extension" do
|
35
|
+
lambda { subject.put("/foo", "Content") }.should raise_error(ArgumentError, "Assets must have a file extension.")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "saves the asset to the filesystem" do
|
39
|
+
lambda { subject.put("/foo.txt", "Content") }.should create_file(File.join(assets_path, "foo.txt")).with_content("Content")
|
40
|
+
end
|
41
|
+
|
42
|
+
it "creates any neccesary parent directories" do
|
43
|
+
lambda { subject.put("/bar/foo.txt", "Content") }.should create_file(File.join(assets_path, "bar", "foo.txt"))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it { should implement(:get, "/foo.txt") }
|
48
|
+
describe "retrieving assets" do
|
49
|
+
it "returns nil if the path provided is not a file with an extension" do
|
50
|
+
subject.get("/foo").should be_nil
|
51
|
+
subject.get("/foo/").should be_nil
|
52
|
+
end
|
53
|
+
|
54
|
+
it "returns nil if the asset did not exist" do
|
55
|
+
subject.get("/foo.txt").should be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it "returns the file's contents if ithe asset does exist" do
|
59
|
+
subject.put("/foo.txt", "Content")
|
60
|
+
subject.get("/foo.txt").should == "Content"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Noumenon::AssetRepository do
|
4
|
+
it "saves any provided on initialization" do
|
5
|
+
repo = Noumenon::AssetRepository.new(option: "set")
|
6
|
+
repo.options[:option].should == "set"
|
7
|
+
end
|
8
|
+
|
9
|
+
it { should_not implement(:put, "/example.txt", "Content").with_message("This repository type does not support saving assets.") }
|
10
|
+
it { should_not implement(:get, "/example.txt").with_message("This repository type does not support loading assets.") }
|
11
|
+
|
12
|
+
it { should implement(:url_for, "/example.txt") }
|
13
|
+
it "returns the default URL below /assets/ when requested" do
|
14
|
+
subject.url_for("/example.txt").should == "/assets/example.txt"
|
15
|
+
end
|
16
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Noumenon::
|
3
|
+
describe Noumenon::ContentRepository::FileSystem do
|
4
4
|
let(:content_path) { File.join(File.dirname(__FILE__), "..", "..", "..", "..", "tmp", "content") }
|
5
5
|
|
6
6
|
around do |example|
|
@@ -10,20 +10,20 @@ describe Noumenon::Repository::FileSystem do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
subject do
|
13
|
-
Noumenon::
|
13
|
+
Noumenon::ContentRepository::FileSystem.new path: content_path
|
14
14
|
end
|
15
15
|
|
16
16
|
describe "initialization" do
|
17
17
|
context "when no path option is provided" do
|
18
18
|
it "should raise an ArgumentError" do
|
19
|
-
lambda { Noumenon::
|
19
|
+
lambda { Noumenon::ContentRepository::FileSystem.new }.should raise_error ArgumentError
|
20
20
|
end
|
21
21
|
|
22
22
|
it "should provide details of the error of how to resolve the error" do
|
23
23
|
begin
|
24
|
-
Noumenon::
|
24
|
+
Noumenon::ContentRepository::FileSystem.new
|
25
25
|
rescue ArgumentError => e
|
26
|
-
e.to_s.should == "You must provide a path to the content repository: Noumenon::
|
26
|
+
e.to_s.should == "You must provide a path to the content repository: Noumenon::ContentRepository::FileSystem.new(path: '/tmp')"
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -173,36 +173,4 @@ describe Noumenon::Repository::FileSystem do
|
|
173
173
|
end
|
174
174
|
end
|
175
175
|
end
|
176
|
-
|
177
|
-
it { should implement(:save_asset, "/foo.txt", "foo") }
|
178
|
-
describe "saving assets" do
|
179
|
-
it "raises an ArgumentError when the path has no extension" do
|
180
|
-
lambda { subject.save_asset("/foo", "Content") }.should raise_error(ArgumentError, "Assets must have a file extension.")
|
181
|
-
end
|
182
|
-
|
183
|
-
it "saves the asset to the filesystem" do
|
184
|
-
lambda { subject.save_asset("/foo.txt", "Content") }.should create_file(File.join(content_path, "assets", "foo.txt")).with_content("Content")
|
185
|
-
end
|
186
|
-
|
187
|
-
it "creates any neccesary parent directories" do
|
188
|
-
lambda { subject.save_asset("/bar/foo.txt", "Content") }.should create_file(File.join(content_path, "assets", "bar", "foo.txt"))
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
it { should implement(:get_asset, "/foo.txt") }
|
193
|
-
describe "retrieving assets" do
|
194
|
-
it "returns nil if the path provided is not a file with an extension" do
|
195
|
-
subject.get_asset("/foo").should be_nil
|
196
|
-
subject.get_asset("/foo/").should be_nil
|
197
|
-
end
|
198
|
-
|
199
|
-
it "returns nil if the asset did not exist" do
|
200
|
-
subject.get_asset("/foo.txt").should be_nil
|
201
|
-
end
|
202
|
-
|
203
|
-
it "returns the file's contents if ithe asset does exist" do
|
204
|
-
subject.save_asset("/foo.txt", "Content")
|
205
|
-
subject.get_asset("/foo.txt").should == "Content"
|
206
|
-
end
|
207
|
-
end
|
208
176
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Noumenon::
|
3
|
+
describe Noumenon::ContentRepository do
|
4
4
|
describe "initialization" do
|
5
5
|
it "allows access to any provided options in #options" do
|
6
|
-
repo = Noumenon::
|
6
|
+
repo = Noumenon::ContentRepository.new(foo: "bar")
|
7
7
|
repo.options[:foo].should == "bar"
|
8
8
|
end
|
9
9
|
end
|
@@ -11,11 +11,4 @@ describe Noumenon::Repository do
|
|
11
11
|
it { should_not implement(:put, "/", foo: "bar").with_message("This repository type does not support updating it's contents.") }
|
12
12
|
it { should_not implement(:get, "/").with_message("This repository type does not support reading it's contents.") }
|
13
13
|
it { should_not implement(:children).with_message("This repository type does not support listing children from a path.") }
|
14
|
-
it { should_not implement(:save_asset, "/example.txt", "Content").with_message("This repository type does not support saving assets.") }
|
15
|
-
it { should_not implement(:get_asset, "/example.txt").with_message("This repository type does not support loading assets.") }
|
16
|
-
|
17
|
-
it { should implement(:asset_url, "/example.txt") }
|
18
|
-
it "returns the default URL below /assets/ when requested" do
|
19
|
-
subject.asset_url("/example.txt").should == "/assets/example.txt"
|
20
|
-
end
|
21
14
|
end
|
data/spec/noumenon_spec.rb
CHANGED
@@ -3,11 +3,11 @@ require 'spec_helper'
|
|
3
3
|
describe Noumenon do
|
4
4
|
describe "accessing the content repository" do
|
5
5
|
it "can be set" do
|
6
|
-
Noumenon.content_repository = Noumenon::
|
6
|
+
Noumenon.content_repository = Noumenon::ContentRepository.new
|
7
7
|
end
|
8
8
|
|
9
9
|
it "can be retrieved" do
|
10
|
-
repo = Noumenon::
|
10
|
+
repo = Noumenon::ContentRepository.new
|
11
11
|
Noumenon.content_repository = repo
|
12
12
|
Noumenon.content_repository.should == repo
|
13
13
|
end
|
@@ -15,13 +15,13 @@ describe Noumenon do
|
|
15
15
|
|
16
16
|
describe "accessing the asset repository" do
|
17
17
|
it "returns the content repository if it has not been set" do
|
18
|
-
Noumenon.content_repository = Noumenon::
|
18
|
+
Noumenon.content_repository = Noumenon::ContentRepository.new
|
19
19
|
Noumenon.asset_repository.should === Noumenon.content_repository
|
20
20
|
end
|
21
21
|
|
22
22
|
it "returns the set asset repository if one has been set" do
|
23
|
-
content = Noumenon::
|
24
|
-
assets = Noumenon::
|
23
|
+
content = Noumenon::ContentRepository.new
|
24
|
+
assets = Noumenon::ContentRepository.new
|
25
25
|
|
26
26
|
Noumenon.content_repository = content
|
27
27
|
Noumenon.asset_repository = assets
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: noumenon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.2.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Jon Wood
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-06-
|
13
|
+
date: 2011-06-08 00:00:00 +01:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -176,7 +176,7 @@ files:
|
|
176
176
|
- README.md
|
177
177
|
- Rakefile
|
178
178
|
- bin/noumenon
|
179
|
-
- features/asset_serving/
|
179
|
+
- features/asset_serving/from_a_repository.feature
|
180
180
|
- features/asset_serving/from_themes.feature
|
181
181
|
- features/generator/site_generator.feature
|
182
182
|
- features/mounted_applications.feature
|
@@ -197,7 +197,8 @@ files:
|
|
197
197
|
- features/template_tags/content_from.feature
|
198
198
|
- features/template_tags/nav_menu.feature
|
199
199
|
- features/template_tags/textilize.feature
|
200
|
-
- generators/repository/
|
200
|
+
- generators/repository/assets/.gitkeep
|
201
|
+
- generators/repository/pages/index.yml
|
201
202
|
- generators/site/Gemfile
|
202
203
|
- generators/site/config.ru
|
203
204
|
- generators/theme/assets/style.css
|
@@ -205,10 +206,12 @@ files:
|
|
205
206
|
- generators/theme/templates/default.nou.html
|
206
207
|
- generators/theme/theme.yml
|
207
208
|
- lib/noumenon.rb
|
209
|
+
- lib/noumenon/asset_repository.rb
|
210
|
+
- lib/noumenon/asset_repository/file_system.rb
|
208
211
|
- lib/noumenon/cli.rb
|
212
|
+
- lib/noumenon/content_repository.rb
|
213
|
+
- lib/noumenon/content_repository/file_system.rb
|
209
214
|
- lib/noumenon/core.rb
|
210
|
-
- lib/noumenon/repository.rb
|
211
|
-
- lib/noumenon/repository/file_system.rb
|
212
215
|
- lib/noumenon/spec.rb
|
213
216
|
- lib/noumenon/spec/example_app.rb
|
214
217
|
- lib/noumenon/spec/example_tags.rb
|
@@ -220,8 +223,10 @@ files:
|
|
220
223
|
- lib/noumenon/theme/assets_middleware.rb
|
221
224
|
- lib/noumenon/version.rb
|
222
225
|
- noumenon.gemspec
|
223
|
-
- spec/noumenon/
|
224
|
-
- spec/noumenon/
|
226
|
+
- spec/noumenon/asset_repository/file_system_spec.rb
|
227
|
+
- spec/noumenon/asset_repository_spec.rb
|
228
|
+
- spec/noumenon/content_repository/file_system_spec.rb
|
229
|
+
- spec/noumenon/content_repository_spec.rb
|
225
230
|
- spec/noumenon/template_spec.rb
|
226
231
|
- spec/noumenon/theme_spec.rb
|
227
232
|
- spec/noumenon_spec.rb
|
@@ -259,7 +264,7 @@ signing_key:
|
|
259
264
|
specification_version: 3
|
260
265
|
summary: A flexible content management system.
|
261
266
|
test_files:
|
262
|
-
- features/asset_serving/
|
267
|
+
- features/asset_serving/from_a_repository.feature
|
263
268
|
- features/asset_serving/from_themes.feature
|
264
269
|
- features/generator/site_generator.feature
|
265
270
|
- features/mounted_applications.feature
|
@@ -280,8 +285,10 @@ test_files:
|
|
280
285
|
- features/template_tags/content_from.feature
|
281
286
|
- features/template_tags/nav_menu.feature
|
282
287
|
- features/template_tags/textilize.feature
|
283
|
-
- spec/noumenon/
|
284
|
-
- spec/noumenon/
|
288
|
+
- spec/noumenon/asset_repository/file_system_spec.rb
|
289
|
+
- spec/noumenon/asset_repository_spec.rb
|
290
|
+
- spec/noumenon/content_repository/file_system_spec.rb
|
291
|
+
- spec/noumenon/content_repository_spec.rb
|
285
292
|
- spec/noumenon/template_spec.rb
|
286
293
|
- spec/noumenon/theme_spec.rb
|
287
294
|
- spec/noumenon_spec.rb
|