ninetails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +17 -0
  4. data/Rakefile +19 -0
  5. data/app/components/ninetails/element.rb +55 -0
  6. data/app/components/ninetails/element_definition.rb +67 -0
  7. data/app/components/ninetails/property.rb +11 -0
  8. data/app/components/ninetails/property_store.rb +22 -0
  9. data/app/components/ninetails/property_type.rb +27 -0
  10. data/app/components/ninetails/section_template.rb +66 -0
  11. data/app/controllers/ninetails/application_controller.rb +4 -0
  12. data/app/controllers/ninetails/page_revisions_controller.rb +31 -0
  13. data/app/controllers/ninetails/pages_controller.rb +14 -0
  14. data/app/controllers/ninetails/section_templates_controller.rb +17 -0
  15. data/app/models/ninetails/page.rb +37 -0
  16. data/app/models/ninetails/page_revision.rb +28 -0
  17. data/app/models/ninetails/page_revision_section.rb +6 -0
  18. data/app/models/ninetails/section.rb +30 -0
  19. data/config/initializers/error_classes.rb +4 -0
  20. data/config/initializers/json_stuff.rb +9 -0
  21. data/config/routes.rb +9 -0
  22. data/db/migrate/20151006093040_create_pages.rb +10 -0
  23. data/db/migrate/20151006093559_create_page_revisions.rb +8 -0
  24. data/db/migrate/20151006093754_create_sections.rb +11 -0
  25. data/db/migrate/20151006094337_create_page_revision_sections.rb +8 -0
  26. data/db/migrate/20151111085201_add_message_to_page_revisions.rb +5 -0
  27. data/db/schema.rb +53 -0
  28. data/lib/ninetails.rb +4 -0
  29. data/lib/ninetails/engine.rb +37 -0
  30. data/lib/ninetails/version.rb +3 -0
  31. data/lib/tasks/ninetails_tasks.rake +8 -0
  32. data/spec/components/element_definition_spec.rb +104 -0
  33. data/spec/components/element_spec.rb +92 -0
  34. data/spec/components/property_spec.rb +34 -0
  35. data/spec/components/property_store_spec.rb +64 -0
  36. data/spec/components/property_type_spec.rb +69 -0
  37. data/spec/components/section_spec.rb +72 -0
  38. data/spec/dummy/Rakefile +6 -0
  39. data/spec/dummy/app/components/element/button.rb +7 -0
  40. data/spec/dummy/app/components/element/button_icon.rb +8 -0
  41. data/spec/dummy/app/components/element/figure.rb +7 -0
  42. data/spec/dummy/app/components/element/meta.rb +7 -0
  43. data/spec/dummy/app/components/element/text.rb +7 -0
  44. data/spec/dummy/app/components/property/icon.rb +8 -0
  45. data/spec/dummy/app/components/property/image.rb +10 -0
  46. data/spec/dummy/app/components/property/link.rb +11 -0
  47. data/spec/dummy/app/components/property/text.rb +8 -0
  48. data/spec/dummy/app/components/section_template/billboard.rb +14 -0
  49. data/spec/dummy/app/components/section_template/document_head.rb +10 -0
  50. data/spec/dummy/bin/bundle +3 -0
  51. data/spec/dummy/bin/rails +4 -0
  52. data/spec/dummy/bin/rake +4 -0
  53. data/spec/dummy/bin/setup +29 -0
  54. data/spec/dummy/config.ru +4 -0
  55. data/spec/dummy/config/application.rb +35 -0
  56. data/spec/dummy/config/boot.rb +5 -0
  57. data/spec/dummy/config/database.yml +12 -0
  58. data/spec/dummy/config/database.yml.travis +4 -0
  59. data/spec/dummy/config/environment.rb +5 -0
  60. data/spec/dummy/config/environments/development.rb +41 -0
  61. data/spec/dummy/config/environments/production.rb +79 -0
  62. data/spec/dummy/config/environments/test.rb +42 -0
  63. data/spec/dummy/config/initializers/assets.rb +11 -0
  64. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  65. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  66. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  67. data/spec/dummy/config/initializers/inflections.rb +16 -0
  68. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  69. data/spec/dummy/config/initializers/session_store.rb +3 -0
  70. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  71. data/spec/dummy/config/locales/en.yml +23 -0
  72. data/spec/dummy/config/routes.rb +3 -0
  73. data/spec/dummy/config/secrets.yml +22 -0
  74. data/spec/dummy/db/schema.rb +53 -0
  75. data/spec/dummy/public/404.html +67 -0
  76. data/spec/dummy/public/422.html +67 -0
  77. data/spec/dummy/public/500.html +66 -0
  78. data/spec/dummy/public/favicon.ico +0 -0
  79. data/spec/factories/page_revisions.rb +8 -0
  80. data/spec/factories/pages.rb +25 -0
  81. data/spec/factories/sections.rb +15 -0
  82. data/spec/models/page_revision_spec.rb +5 -0
  83. data/spec/models/page_spec.rb +26 -0
  84. data/spec/models/section_spec.rb +113 -0
  85. data/spec/rails_helper.rb +60 -0
  86. data/spec/requests/page_revisions_spec.rb +117 -0
  87. data/spec/requests/pages_spec.rb +68 -0
  88. data/spec/requests/section_templates_spec.rb +17 -0
  89. data/spec/spec_helper.rb +98 -0
  90. data/spec/support/factory_girl.rb +5 -0
  91. data/spec/support/request_helpers.rb +9 -0
  92. data/spec/support/shared_examples.rb +34 -0
  93. metadata +378 -0
@@ -0,0 +1,64 @@
1
+ require 'rails_helper'
2
+
3
+ class NoPropertiesDefined
4
+ include Ninetails::PropertyStore
5
+ end
6
+
7
+ class SomeProperties
8
+ include Ninetails::PropertyStore
9
+ property :text, Property::Text
10
+ end
11
+
12
+ class PropertiesWithValidations
13
+ include Ninetails::PropertyStore
14
+ property :text, String
15
+ validates :text, presence: true
16
+ end
17
+
18
+ describe Ninetails::PropertyStore do
19
+
20
+ it "should expose a list of properties on the class" do
21
+ expect(NoPropertiesDefined).to respond_to :properties
22
+ end
23
+
24
+ it "should have an empty array of properties to begin with" do
25
+ expect(NoPropertiesDefined.properties).to eq []
26
+ end
27
+
28
+ it "should store properties using Ninetails::PropertyType" do
29
+ expect(SomeProperties.properties.first).to be_a Ninetails::PropertyType
30
+ end
31
+
32
+ it "should store the name of a defined property" do
33
+ expect(SomeProperties.properties.first.name).to eq :text
34
+ end
35
+
36
+ it "should store the type of a defined property" do
37
+ expect(SomeProperties.properties.first.type).to eq Property::Text
38
+ end
39
+
40
+ it "should store the property as a virtus attribute" do
41
+ virtus_attr = SomeProperties.attribute_set.first
42
+ expect(virtus_attr.name).to eq :text
43
+ expect(virtus_attr.primitive).to eq Property::Text
44
+ end
45
+
46
+ describe "validations" do
47
+
48
+ let(:prop) { PropertiesWithValidations.new text: nil }
49
+
50
+ before do
51
+ prop.valid? # run validations
52
+ end
53
+
54
+ it "should be possible to validate the propery group" do
55
+ expect(prop.valid?).to be false
56
+ end
57
+
58
+ it "should list errors using ActiveModel::Errors" do
59
+ expect(prop.errors.size).to eq 1
60
+ end
61
+
62
+ end
63
+
64
+ end
@@ -0,0 +1,69 @@
1
+ require 'rails_helper'
2
+
3
+ class TextProperty
4
+ include Ninetails::PropertyStore
5
+ property :text, String
6
+ end
7
+
8
+ describe Ninetails::PropertyType do
9
+
10
+ let(:string_property) { Ninetails::PropertyType.new :foo, String }
11
+ let(:text_property) { Ninetails::PropertyType.new :foo, TextProperty }
12
+
13
+ it "should be initializable with name and type" do
14
+ expect(string_property.name).to eq :foo
15
+ expect(string_property.type).to eq String
16
+ end
17
+
18
+ describe "serializing" do
19
+ it "should be a new instance of the type when the type does not respond to #structure" do
20
+ expect(string_property.serialize).to eq ""
21
+ end
22
+
23
+ it "should use the structure when the type responds to #structure" do
24
+ allow(String).to receive(:respond_to?) { true }
25
+ allow(String).to receive(:serialize) { "HELLO" }
26
+ expect(string_property.serialize).to eq "HELLO"
27
+ end
28
+
29
+ it "should initialize a new instance of the type with the serialized_values attribute as an argument" do
30
+ string_property.serialized_values = "123"
31
+ expect(string_property.serialize).to eq "123"
32
+ end
33
+ end
34
+
35
+ describe "property" do
36
+ it "should be set to a new instance of the property type" do
37
+ expect(string_property.property).to be_a String
38
+ expect(text_property.property).to be_a TextProperty
39
+ end
40
+ end
41
+
42
+ describe "handling serialized values" do
43
+ it "should be nil when initializing a Ninetails::PropertyType" do
44
+ expect(string_property.serialized_values).to eq nil
45
+ end
46
+
47
+ it "should be possible to set" do
48
+ string_property.serialized_values = "foobar"
49
+ expect(string_property.serialized_values).to eq "foobar"
50
+ end
51
+
52
+ it "should raise a TypeError if you try to set the wrong type" do
53
+ expect {
54
+ string_property.serialized_values = { foo: "bar" }
55
+ }.to raise_error(TypeError)
56
+ end
57
+
58
+ it "should be possible to set with a hash if the property conforms to the Ninetails::PropertyStore" do
59
+ text_property.serialized_values = { text: "hello" }
60
+ expect(text_property.serialized_values).to eq({ text: "hello" })
61
+ end
62
+
63
+ it "should use the serialized_values to reinitialize the property" do
64
+ text_property.serialized_values = { text: "hello" }
65
+ expect(text_property.property.text).to eq "hello"
66
+ end
67
+ end
68
+
69
+ end
@@ -0,0 +1,72 @@
1
+ require 'rails_helper'
2
+
3
+ class ExampleSection < Ninetails::SectionTemplate
4
+ located_in :body
5
+ has_element :foo, Element::Text
6
+ has_element :bar, Element::Button
7
+ end
8
+
9
+ RSpec.describe Ninetails::SectionTemplate do
10
+
11
+ describe "position" do
12
+ it "should be possible to set" do
13
+ expect(ExampleSection.position).to eq :body
14
+ end
15
+
16
+ it "should raise an exception if the position is not one of head or body" do
17
+ expect{ ExampleSection.located_in(:a_cave) }.to raise_error(Ninetails::SectionConfigurationError)
18
+ end
19
+ end
20
+
21
+ describe "elements" do
22
+ it "should store elements as a Array" do
23
+ expect(ExampleSection.elements).to be_a Array
24
+ end
25
+
26
+ it "should store the element names" do
27
+ expect(ExampleSection.elements[0].name).to eq :foo
28
+ expect(ExampleSection.elements[1].name).to eq :bar
29
+ end
30
+
31
+ it "should store the element types" do
32
+ expect(ExampleSection.elements[0].type).to eq Element::Text
33
+ expect(ExampleSection.elements[1].type).to eq Element::Button
34
+ end
35
+ end
36
+
37
+ describe "elements structure" do
38
+ before do
39
+ # Mock SecureRandom so we can reliably compare property strucures without worrying about
40
+ # references which don't match
41
+ allow(SecureRandom).to receive(:uuid) { "123" }
42
+ end
43
+
44
+ let(:structure) { ExampleSection.new.serialize_elements }
45
+
46
+ it "should be a hash" do
47
+ expect(structure).to be_a(Hash)
48
+ end
49
+
50
+ it "should have the property structure for each element" do
51
+ expect(structure[:foo]).to eq Ninetails::ElementDefinition.new(:bogus, Element::Text, :single).properties_structure
52
+ expect(structure[:bar]).to eq Ninetails::ElementDefinition.new(:bogus, Element::Button, :single).properties_structure
53
+ end
54
+ end
55
+
56
+ describe "structure" do
57
+ let(:structure) { ExampleSection.new.serialize }
58
+
59
+ it "should have a type key which is the section class name" do
60
+ expect(structure[:type]).to eq "ExampleSection"
61
+ end
62
+
63
+ it "should include the position in tags" do
64
+ expect(structure[:tags][:position]).to eq ExampleSection.position
65
+ end
66
+
67
+ it "should have an elements key which contains the section's elements" do
68
+ expect(structure[:elements]).to eq ExampleSection.new.serialize_elements
69
+ end
70
+ end
71
+
72
+ end
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,7 @@
1
+ module Element
2
+ class Button < Ninetails::Element
3
+
4
+ property :link, Property::Link
5
+
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ module Element
2
+ class ButtonIcon < Ninetails::Element
3
+
4
+ property :link, Property::Link
5
+ property :icon, Property::Icon
6
+
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ module Element
2
+ class Figure < Ninetails::Element
3
+
4
+ property :image, Property::Image
5
+
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Element
2
+ class Meta < Ninetails::Element
3
+
4
+ property :content, Property::Text
5
+
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Element
2
+ class Text < Ninetails::Element
3
+
4
+ property :content, Property::Text
5
+
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ module Property
2
+ class Icon < Ninetails::Property
3
+
4
+ property :name, String
5
+ validates :name, presence: true
6
+
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ module Property
2
+ class Image < Ninetails::Property
3
+
4
+ property :src, String
5
+ property :alt, String
6
+
7
+ validates :src, :alt, presence: true
8
+
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module Property
2
+ class Link < Ninetails::Property
3
+
4
+ property :url, String
5
+ property :title, String
6
+ property :text, String
7
+
8
+ validates :url, :title, :text, presence: true
9
+
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ module Property
2
+ class Text < Ninetails::Property
3
+
4
+ property :text, String
5
+ validates :text, presence: true
6
+
7
+ end
8
+ end
@@ -0,0 +1,14 @@
1
+ module SectionTemplate
2
+ class Billboard < Ninetails::SectionTemplate
3
+
4
+ located_in :body
5
+
6
+ has_element :title, Element::Text
7
+ has_element :background_image, Element::Figure
8
+ has_element :signup_button, Element::Button
9
+
10
+ has_many_elements :supported_card_icons, Element::Figure
11
+ has_many_elements :supported_device_icons, Element::Figure
12
+
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ module SectionTemplate
2
+ class DocumentHead < Ninetails::SectionTemplate
3
+
4
+ located_in :head
5
+
6
+ has_element :title, Element::Text
7
+ has_element :description, Element::Meta
8
+
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3
+ load Gem.bin_path('bundler', 'bundle')
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
3
+ require_relative '../config/boot'
4
+ require 'rails/commands'
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../config/boot'
3
+ require 'rake'
4
+ Rake.application.run
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pathname'
3
+
4
+ # path to your application root.
5
+ APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
6
+
7
+ Dir.chdir APP_ROOT do
8
+ # This script is a starting point to setup your application.
9
+ # Add necessary setup steps to this file:
10
+
11
+ puts "== Installing dependencies =="
12
+ system "gem install bundler --conservative"
13
+ system "bundle check || bundle install"
14
+
15
+ # puts "\n== Copying sample files =="
16
+ # unless File.exist?("config/database.yml")
17
+ # system "cp config/database.yml.sample config/database.yml"
18
+ # end
19
+
20
+ puts "\n== Preparing database =="
21
+ system "bin/rake db:setup"
22
+
23
+ puts "\n== Removing old logs and tempfiles =="
24
+ system "rm -f log/*"
25
+ system "rm -rf tmp/cache"
26
+
27
+ puts "\n== Restarting application server =="
28
+ system "touch tmp/restart.txt"
29
+ end
@@ -0,0 +1,4 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require ::File.expand_path('../config/environment', __FILE__)
4
+ run Rails.application
@@ -0,0 +1,35 @@
1
+ require File.expand_path('../boot', __FILE__)
2
+
3
+ require 'rails/all'
4
+
5
+ Bundler.require(*Rails.groups)
6
+ require "ninetails"
7
+
8
+ module Dummy
9
+ class Application < Rails::Application
10
+ # Settings in config/environments/* take precedence over those specified here.
11
+ # Application configuration should go into files in config/initializers
12
+ # -- all .rb files in that directory are automatically loaded.
13
+
14
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
15
+ # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
16
+ # config.time_zone = 'Central Time (US & Canada)'
17
+
18
+ # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
19
+ # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
20
+ # config.i18n.default_locale = :de
21
+
22
+ # Do not swallow errors in after_commit/after_rollback callbacks.
23
+ config.active_record.raise_in_transactional_callbacks = true
24
+
25
+ config.autoload_paths += [
26
+ "#{config.root}/app/components"
27
+ ]
28
+
29
+ config.eager_load_paths = [
30
+ Rails.root.join("app/controllers").to_s,
31
+ Rails.root.join("app/components").to_s,
32
+ Rails.root.join("app/models").to_s
33
+ ]
34
+ end
35
+ end
@@ -0,0 +1,5 @@
1
+ # Set up gems listed in the Gemfile.
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)
3
+
4
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5
+ $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)
@@ -0,0 +1,12 @@
1
+ default: &default
2
+ adapter: postgresql
3
+ encoding: unicode
4
+ pool: 5
5
+
6
+ development:
7
+ <<: *default
8
+ database: ninetails_dummy_development
9
+
10
+ test:
11
+ <<: *default
12
+ database: ninetails_dummy_test
@@ -0,0 +1,4 @@
1
+ test:
2
+ adapter: postgresql
3
+ database: ninetails_dummy_test
4
+ username: postgres