ninetails 0.0.1

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.
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