ninetails 0.0.2 → 0.1.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.
- checksums.yaml +4 -4
- data/README.md +27 -4
- data/Rakefile +3 -3
- data/app/components/ninetails/element.rb +5 -1
- data/app/components/ninetails/element_definition.rb +2 -2
- data/app/components/ninetails/property_type.rb +0 -2
- data/app/components/ninetails/{section_template.rb → section.rb} +6 -8
- data/app/controllers/ninetails/application_controller.rb +1 -0
- data/app/controllers/ninetails/page_revisions_controller.rb +2 -3
- data/app/controllers/ninetails/pages_controller.rb +20 -1
- data/app/controllers/ninetails/sections_controller.rb +35 -0
- data/app/models/ninetails/page.rb +3 -16
- data/app/models/ninetails/page_revision.rb +2 -8
- data/app/models/ninetails/page_revision_section.rb +1 -1
- data/app/models/ninetails/page_section.rb +40 -0
- data/app/views/ninetails/page_revisions/index.json.jbuilder +1 -0
- data/app/views/ninetails/pages/_page.json.jbuilder +13 -0
- data/app/views/ninetails/pages/index.json.jbuilder +1 -0
- data/app/views/ninetails/pages/show.json.jbuilder +1 -0
- data/app/views/ninetails/sections/_section.json.jbuilder +1 -0
- data/app/views/ninetails/sections/validate.json.jbuilder +3 -0
- data/config/routes.rb +9 -5
- data/config/spring.rb +1 -0
- data/db/migrate/20151120120538_rename_sections_to_page_sections.rb +5 -0
- data/lib/ninetails/config.rb +8 -0
- data/lib/ninetails/engine.rb +5 -0
- data/lib/ninetails/key_conversion.rb +28 -0
- data/lib/ninetails/version.rb +1 -1
- data/lib/tasks/ninetails_tasks.rake +2 -2
- data/spec/components/element_spec.rb +3 -3
- data/spec/components/property_spec.rb +2 -2
- data/spec/components/property_type_spec.rb +5 -5
- data/spec/components/section_spec.rb +2 -2
- data/spec/dummy/app/components/{section_template → section}/billboard.rb +2 -2
- data/spec/dummy/app/components/{section_template → section}/document_head.rb +2 -2
- data/spec/dummy/app/components/section/minimal_billboard.rb +9 -0
- data/spec/dummy/bin/rails +5 -0
- data/spec/dummy/bin/rake +5 -0
- data/spec/dummy/bin/rspec +8 -0
- data/spec/dummy/bin/spring +15 -0
- data/spec/dummy/config/application.rb +0 -10
- data/spec/dummy/config/initializers/ninetails.rb +1 -0
- data/spec/dummy/config/spring.rb +1 -0
- data/spec/dummy/db/schema.rb +10 -10
- data/spec/dummy/log/development.log +2499 -0
- data/spec/dummy/log/test.log +55690 -0
- data/spec/factories/page_sections.rb +15 -0
- data/spec/models/{section_spec.rb → page_section_spec.rb} +17 -36
- data/spec/models/page_spec.rb +9 -14
- data/spec/requests/middleware_spec.rb +80 -0
- data/spec/requests/page_revisions_spec.rb +41 -42
- data/spec/requests/pages_spec.rb +54 -1
- data/spec/requests/sections_spec.rb +32 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/support/section_helpers.rb +27 -0
- metadata +74 -35
- data/app/controllers/ninetails/section_templates_controller.rb +0 -17
- data/app/models/ninetails/section.rb +0 -30
- data/db/schema.rb +0 -53
- data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
- data/spec/dummy/config/initializers/inflections.rb +0 -16
- data/spec/dummy/config/initializers/mime_types.rb +0 -4
- data/spec/dummy/config/locales/en.yml +0 -23
- data/spec/dummy/public/404.html +0 -67
- data/spec/dummy/public/422.html +0 -67
- data/spec/dummy/public/500.html +0 -66
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/factories/sections.rb +0 -15
- data/spec/requests/section_templates_spec.rb +0 -17
@@ -0,0 +1,15 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
|
3
|
+
factory :document_head_section, class: Ninetails::PageSection do
|
4
|
+
type "DocumentHead"
|
5
|
+
tags Section::DocumentHead.new.tags
|
6
|
+
elements Section::DocumentHead.new.serialize_elements
|
7
|
+
end
|
8
|
+
|
9
|
+
factory :billboard_section, class: Ninetails::PageSection do
|
10
|
+
type "Billboard"
|
11
|
+
tags Section::Billboard.new.tags
|
12
|
+
elements Section::Billboard.new.serialize_elements
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'rails_helper'
|
2
2
|
|
3
|
-
module
|
4
|
-
class TestSection < Ninetails::
|
3
|
+
module Section
|
4
|
+
class TestSection < Ninetails::Section
|
5
5
|
located_in :body
|
6
6
|
has_element :headline, Element::Text
|
7
7
|
has_element :button, Element::Button
|
@@ -9,7 +9,7 @@ module SectionTemplate
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
RSpec.describe Ninetails::
|
12
|
+
RSpec.describe Ninetails::PageSection, type: :model do
|
13
13
|
|
14
14
|
describe "deserializing a json blob" do
|
15
15
|
let(:headline) { "Hello world!" }
|
@@ -48,42 +48,42 @@ RSpec.describe Ninetails::Section, type: :model do
|
|
48
48
|
}
|
49
49
|
end
|
50
50
|
|
51
|
-
let(:section) { Ninetails::
|
51
|
+
let(:section) { Ninetails::PageSection.new(json) }
|
52
52
|
|
53
|
-
it "should create a
|
53
|
+
it "should create a Section instance" do
|
54
54
|
section.deserialize
|
55
|
-
expect(section.
|
55
|
+
expect(section.section).to be_a Section::TestSection
|
56
56
|
end
|
57
57
|
|
58
58
|
it "should have an array of elements_instances" do
|
59
59
|
section.deserialize
|
60
|
-
expect(section.
|
60
|
+
expect(section.section.elements_instances.size).to eq 3
|
61
61
|
end
|
62
62
|
|
63
63
|
it "should include an element for 'text', 'button', and 'link'" do
|
64
64
|
section.deserialize
|
65
|
-
expect(section.
|
66
|
-
expect(section.
|
67
|
-
expect(section.
|
65
|
+
expect(section.section.elements_instances[0].name).to eq :headline
|
66
|
+
expect(section.section.elements_instances[1].name).to eq :button
|
67
|
+
expect(section.section.elements_instances[2].name).to eq :messages
|
68
68
|
end
|
69
69
|
|
70
70
|
it "should be the correct type for 'text', 'button', and 'link'" do
|
71
71
|
section.deserialize
|
72
|
-
expect(section.
|
73
|
-
expect(section.
|
74
|
-
expect(section.
|
72
|
+
expect(section.section.elements_instances[0].type).to eq Element::Text
|
73
|
+
expect(section.section.elements_instances[1].type).to eq Element::Button
|
74
|
+
expect(section.section.elements_instances[2].type).to eq Element::Text
|
75
75
|
end
|
76
76
|
|
77
77
|
it "should call deserialize on each element" do
|
78
|
-
expect(
|
79
|
-
expect(
|
80
|
-
expect(
|
78
|
+
expect(Section::TestSection.find_element("headline")).to receive(:deserialize).with(json["elements"]["headline"])
|
79
|
+
expect(Section::TestSection.find_element("button")).to receive(:deserialize).with(json["elements"]["button"])
|
80
|
+
expect(Section::TestSection.find_element("messages")).to receive(:deserialize).with(json["elements"]["messages"])
|
81
81
|
section.deserialize
|
82
82
|
end
|
83
83
|
|
84
84
|
it "should be possible to reserialize into json" do
|
85
85
|
section.deserialize
|
86
|
-
serialized = section.
|
86
|
+
serialized = section.section.serialize.with_indifferent_access
|
87
87
|
expect(serialized[:elements][:headline][:content][:text]).to eq headline
|
88
88
|
expect(serialized[:elements][:messages][0][:content][:text]).to eq first_message
|
89
89
|
expect(serialized[:elements][:messages][1][:content][:text]).to eq second_message
|
@@ -91,23 +91,4 @@ RSpec.describe Ninetails::Section, type: :model do
|
|
91
91
|
|
92
92
|
end
|
93
93
|
|
94
|
-
describe "building json" do
|
95
|
-
|
96
|
-
let(:section) { build :document_head_section }
|
97
|
-
let(:json) do
|
98
|
-
{
|
99
|
-
id: section.id,
|
100
|
-
name: section.name,
|
101
|
-
type: section.type,
|
102
|
-
tags: section.tags,
|
103
|
-
elements: section.elements
|
104
|
-
}.to_json
|
105
|
-
end
|
106
|
-
|
107
|
-
it "should build the section into json" do
|
108
|
-
expect(section.to_builder.target!).to eq json
|
109
|
-
end
|
110
|
-
|
111
|
-
end
|
112
|
-
|
113
94
|
end
|
data/spec/models/page_spec.rb
CHANGED
@@ -2,23 +2,18 @@ require 'rails_helper'
|
|
2
2
|
|
3
3
|
RSpec.describe Ninetails::Page, type: :model do
|
4
4
|
|
5
|
-
describe "
|
5
|
+
describe "validations" do
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
id: page.id,
|
12
|
-
name: page.name,
|
13
|
-
url: page.url,
|
14
|
-
revisionId: page.revision.id,
|
15
|
-
sections: page.sections_to_builder
|
16
|
-
}
|
17
|
-
}.to_json
|
7
|
+
it "should require a url" do
|
8
|
+
new_page = Ninetails::Page.new url: nil
|
9
|
+
expect(new_page.valid?).to be false
|
10
|
+
expect(new_page.errors[:url]).to eq ["can't be blank"]
|
18
11
|
end
|
19
12
|
|
20
|
-
it "should
|
21
|
-
|
13
|
+
it "should require a unique url" do
|
14
|
+
new_page = Ninetails::Page.new url: create(:page).url
|
15
|
+
expect(new_page.valid?).to be false
|
16
|
+
expect(new_page.errors[:url]).to eq ["has already been taken"]
|
22
17
|
end
|
23
18
|
|
24
19
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require "rails_helper"
|
2
|
+
|
3
|
+
module Ninetails
|
4
|
+
class TestController < ApplicationController
|
5
|
+
def index
|
6
|
+
render json: {
|
7
|
+
foo_bar: "baz_box",
|
8
|
+
hello_world: {
|
9
|
+
this_is_dog_fort: "Checking in"
|
10
|
+
}
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
def show
|
15
|
+
render text: "foo_bar"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class DummyController < ActionController::Base
|
21
|
+
def index
|
22
|
+
render json: {
|
23
|
+
this_is_a_key: "thanks"
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "Key conversion middleware" do
|
29
|
+
|
30
|
+
# Add the Ninetails::TestController and DummyController stuff to routes
|
31
|
+
before do
|
32
|
+
Ninetails::Engine.routes.send(:eval_block, -> {
|
33
|
+
get "/test", to: "test#index"
|
34
|
+
get "/test/foo", to: "test#show"
|
35
|
+
})
|
36
|
+
|
37
|
+
Dummy::Application.routes.send(:eval_block, -> {
|
38
|
+
get "/dummy", to: "dummy#index"
|
39
|
+
})
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "when Ninetails::Config.key_style is camelcase" do
|
43
|
+
before do
|
44
|
+
Ninetails::Config.key_style = :camelcase
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should convert all keys to camelcase" do
|
48
|
+
get "/test"
|
49
|
+
expect(json).to have_key "fooBar"
|
50
|
+
expect(json["helloWorld"]).to have_key "thisIsDogFort"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should not modify non-json responses" do
|
54
|
+
get "/test/foo"
|
55
|
+
expect(response.body).to eq "foo_bar"
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should not modify responses from outside of the Ninetails engine" do
|
59
|
+
get "/dummy"
|
60
|
+
expect(json).to have_key "this_is_a_key"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "when Ninetails::Config.key_style is underscore" do
|
65
|
+
before do
|
66
|
+
Ninetails::Config.key_style = :underscore
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should not modify any response from Ninetails" do
|
70
|
+
get "/test"
|
71
|
+
expect(json).to have_key "foo_bar"
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should not modify any response from the parent app" do
|
75
|
+
get "/dummy"
|
76
|
+
expect(json).to have_key "this_is_a_key"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -25,27 +25,7 @@ describe "Page Revisions API" do
|
|
25
25
|
"page_revision": {
|
26
26
|
"message": "",
|
27
27
|
"sections":[
|
28
|
-
|
29
|
-
"name": "",
|
30
|
-
"type": "DocumentHead",
|
31
|
-
"tags": {
|
32
|
-
"position": "head"
|
33
|
-
},
|
34
|
-
"elements": {
|
35
|
-
"title": {
|
36
|
-
"type": "Text",
|
37
|
-
"content": {
|
38
|
-
"text": "iZettle – Accept credit card payments with your iPhone, iPad or Android"
|
39
|
-
}
|
40
|
-
},
|
41
|
-
"description": {
|
42
|
-
"type": "Meta",
|
43
|
-
"content": {
|
44
|
-
"text": "Accept credit card payments on the go with iZettle. All you need is a smartphone or a tablet and our free app."
|
45
|
-
}
|
46
|
-
}
|
47
|
-
}
|
48
|
-
}
|
28
|
+
document_head_section
|
49
29
|
]
|
50
30
|
}
|
51
31
|
}
|
@@ -56,27 +36,7 @@ describe "Page Revisions API" do
|
|
56
36
|
"page_revision": {
|
57
37
|
"message": "",
|
58
38
|
"sections":[
|
59
|
-
|
60
|
-
"name": "",
|
61
|
-
"type": "DocumentHead",
|
62
|
-
"tags": {
|
63
|
-
"position": "head"
|
64
|
-
},
|
65
|
-
"elements": {
|
66
|
-
"title": {
|
67
|
-
"type": "Text",
|
68
|
-
"content": {
|
69
|
-
"text": ""
|
70
|
-
}
|
71
|
-
},
|
72
|
-
"description": {
|
73
|
-
"type": "Meta",
|
74
|
-
"content": {
|
75
|
-
"text": ""
|
76
|
-
}
|
77
|
-
}
|
78
|
-
}
|
79
|
-
}
|
39
|
+
document_head_section(title: "", description: "")
|
80
40
|
]
|
81
41
|
}
|
82
42
|
}
|
@@ -114,4 +74,43 @@ describe "Page Revisions API" do
|
|
114
74
|
end
|
115
75
|
end
|
116
76
|
|
77
|
+
describe "handling hash keys in camelcase" do
|
78
|
+
|
79
|
+
let(:camelcased_revision) do
|
80
|
+
{
|
81
|
+
page_revision: {
|
82
|
+
message: "",
|
83
|
+
sections: [
|
84
|
+
{
|
85
|
+
"name": "",
|
86
|
+
"type": "MinimalBillboard",
|
87
|
+
"tags": {
|
88
|
+
"position": "body"
|
89
|
+
},
|
90
|
+
"elements": {
|
91
|
+
"backgroundImage": {
|
92
|
+
"type": "Figure",
|
93
|
+
"image": {
|
94
|
+
"src": "/foobar.jpg",
|
95
|
+
"alt": "Hello world"
|
96
|
+
}
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
]
|
101
|
+
}
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should not cause problems" do
|
106
|
+
expect {
|
107
|
+
post "/pages/#{page.id}/revisions", camelcased_revision
|
108
|
+
}.to change { page.revisions.count }.by(1)
|
109
|
+
|
110
|
+
expect(response).to be_success
|
111
|
+
expect(json["page"]["revisionId"]).to_not be_nil
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
117
116
|
end
|
data/spec/requests/pages_spec.rb
CHANGED
@@ -5,13 +5,66 @@ describe "Pages API" do
|
|
5
5
|
let(:page) { create :page }
|
6
6
|
let(:page_url) { "/pages/#{CGI.escape(page.url)}" }
|
7
7
|
|
8
|
+
describe "listing pages" do
|
9
|
+
before do
|
10
|
+
create_list :page, 5
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return the correct number of pages" do
|
14
|
+
get "/pages"
|
15
|
+
expect(response).to be_success
|
16
|
+
expect(json["pages"].size).to eq Ninetails::Page.count
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should include the id and url for each page" do
|
20
|
+
get "/pages"
|
21
|
+
|
22
|
+
json["pages"].each do |page|
|
23
|
+
expect(page).to have_key "id"
|
24
|
+
expect(page).to have_key "url"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "creating a page" do
|
30
|
+
|
31
|
+
let(:valid_page_params) do
|
32
|
+
{
|
33
|
+
page: {
|
34
|
+
url: "/foobar"
|
35
|
+
}
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
let(:existing_page_url_params) do
|
40
|
+
{
|
41
|
+
page: {
|
42
|
+
url: page.url
|
43
|
+
}
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should save the page if it is valid" do
|
48
|
+
expect {
|
49
|
+
post "/pages", valid_page_params
|
50
|
+
}.to change{ Ninetails::Page.count }.by(1)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should show errors if the url is taken" do
|
54
|
+
post "/pages", existing_page_url_params
|
55
|
+
|
56
|
+
expect(response).to_not be_success
|
57
|
+
expect(json["page"]["errors"]["url"]).not_to be_empty
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
8
62
|
describe "when not specifying revision" do
|
9
63
|
describe "when the page exists" do
|
10
64
|
it "should return the current revision of a page" do
|
11
65
|
get page_url
|
12
66
|
|
13
67
|
expect(response).to be_success
|
14
|
-
expect(response.body).to eq page.to_builder.target!
|
15
68
|
expect(json["page"]["revisionId"]).to eq page.current_revision.id
|
16
69
|
end
|
17
70
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe "Sections API" do
|
4
|
+
|
5
|
+
it "should list the available sections" do
|
6
|
+
get "/sections"
|
7
|
+
expect(response).to be_success
|
8
|
+
billboard_json = json["sections"].find { |s| s["type"] == "Billboard" }.to_json
|
9
|
+
expect(billboard_json).to eq Section::Billboard.new.serialize.to_json
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should be possible to get a section's structure" do
|
13
|
+
get "/sections/Billboard"
|
14
|
+
expect(response).to be_success
|
15
|
+
expect(response.body).to eq Section::Billboard.new.serialize.to_json
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "validating" do
|
19
|
+
it "should return no errors when the section is valid" do
|
20
|
+
post "/sections/validate", section: document_head_section
|
21
|
+
expect(response).to be_success
|
22
|
+
expect(json["section"]["elements"]["title"]["content"]).not_to have_key "errors"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should return errors when the section is invalid" do
|
26
|
+
post "/sections/validate", section: document_head_section(title: "")
|
27
|
+
expect(response).not_to be_success
|
28
|
+
expect(json["section"]["elements"]["title"]["content"]).to have_key "errors"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
ENV["RAILS_ENV"] = "test"
|
2
2
|
|
3
|
+
require "codeclimate-test-reporter"
|
4
|
+
CodeClimate::TestReporter.start
|
5
|
+
|
3
6
|
Dir["./spec/support/**/*.rb"].sort.each { |f| require f}
|
4
7
|
|
5
8
|
# This file was generated by the `rails generate rspec:install` command. Conventionally, all
|
@@ -95,4 +98,5 @@ RSpec.configure do |config|
|
|
95
98
|
=end
|
96
99
|
|
97
100
|
config.include Requests::JsonHelpers, type: :request
|
101
|
+
config.include SectionHelpers
|
98
102
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module SectionHelpers
|
2
|
+
|
3
|
+
def document_head_section(title: "Title text", description: "Description text")
|
4
|
+
{
|
5
|
+
"name": "",
|
6
|
+
"type": "DocumentHead",
|
7
|
+
"tags": {
|
8
|
+
"position": "head"
|
9
|
+
},
|
10
|
+
"elements": {
|
11
|
+
"title": {
|
12
|
+
"type": "Text",
|
13
|
+
"content": {
|
14
|
+
"text": title
|
15
|
+
}
|
16
|
+
},
|
17
|
+
"description": {
|
18
|
+
"type": "Meta",
|
19
|
+
"content": {
|
20
|
+
"text": description
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|