contents_core 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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +101 -0
- data/Rakefile +36 -0
- data/app/models/contents_core/application_record.rb +5 -0
- data/app/models/contents_core/block.rb +170 -0
- data/app/models/contents_core/item.rb +50 -0
- data/app/models/contents_core/item_boolean.rb +23 -0
- data/app/models/contents_core/item_datetime.rb +14 -0
- data/app/models/contents_core/item_file.rb +46 -0
- data/app/models/contents_core/item_float.rb +23 -0
- data/app/models/contents_core/item_hash.rb +16 -0
- data/app/models/contents_core/item_integer.rb +23 -0
- data/app/models/contents_core/item_string.rb +29 -0
- data/app/models/contents_core/item_text.rb +19 -0
- data/config/initializers/contents_core.rb +73 -0
- data/config/routes.rb +4 -0
- data/db/migrate/20170414173603_create_contents_core_blocks.rb +17 -0
- data/db/migrate/20170414173610_create_contents_core_items.rb +11 -0
- data/db/migrate/20170414173611_add_extra_items.rb +12 -0
- data/lib/contents_core.rb +14 -0
- data/lib/contents_core/blocks.rb +34 -0
- data/lib/contents_core/engine.rb +7 -0
- data/lib/contents_core/version.rb +3 -0
- data/lib/tasks/contents_core_tasks.rake +4 -0
- metadata +83 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA1:
         | 
| 3 | 
            +
              metadata.gz: 3e33ec3a230bad84970e4f2b43fe3c700e9ff72a
         | 
| 4 | 
            +
              data.tar.gz: 9d3f7d53a033c6d52b5d22f580ec3210c90c17a0
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: 566cb403e239475914c934bd85dd1fb37a1a37ad50ede3ca7701f24c61ebcabb96de6e4ee171ebb90dc53700c0bf745fa1ed71b32bd2cef70ce6172399d7cf95
         | 
| 7 | 
            +
              data.tar.gz: f07a30421f8d0de813666cc48d0d5b00902d8f07f87553abdf85f17c30a306fec0bda45bcec911ecb9776561181825dd446b440037c27b38b7bb7adf253a6263
         | 
    
        data/MIT-LICENSE
    ADDED
    
    | @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            Copyright 2017 
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining
         | 
| 4 | 
            +
            a copy of this software and associated documentation files (the
         | 
| 5 | 
            +
            "Software"), to deal in the Software without restriction, including
         | 
| 6 | 
            +
            without limitation the rights to use, copy, modify, merge, publish,
         | 
| 7 | 
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 8 | 
            +
            permit persons to whom the Software is furnished to do so, subject to
         | 
| 9 | 
            +
            the following conditions:
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            The above copyright notice and this permission notice shall be
         | 
| 12 | 
            +
            included in all copies or substantial portions of the Software.
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 15 | 
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 16 | 
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| 17 | 
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         | 
| 18 | 
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         | 
| 19 | 
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         | 
| 20 | 
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         | 
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,101 @@ | |
| 1 | 
            +
            # ContentsCore
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            A Rails gem which offer a simple structure to manage contents in a flexible way.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            _NOTE_: this is an **ALPHA** version, major changes could happens - this is a refactoring of another gem of mine (editable_components)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            Goals:
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            - attach the necessary data to a model transparently
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            - simplify the components development in views
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            - add blocks / items (= fields) without migrations
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            ### Install
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            - Add to the Gemfile:
         | 
| 18 | 
            +
            `gem 'contents_core'`
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            - Copy migrations (Rails 5.x syntax, in Rails 4.x use `rake`):
         | 
| 21 | 
            +
            `rails contents_core:install:migrations`
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            - Migrate
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            - Add the concern *Blocks* to your model: `include ContentsCore::Blocks`
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            ### Config
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            Edit the conf file: `config/initializers/contents_core.rb`
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            ```ruby
         | 
| 32 | 
            +
            conf = ContentsCore.config
         | 
| 33 | 
            +
            # Adds a new custom block
         | 
| 34 | 
            +
            conf[:cc_blocks][:custom] = {
         | 
| 35 | 
            +
              name: 'Custom block',
         | 
| 36 | 
            +
              items: {
         | 
| 37 | 
            +
                int1: :item_integer,
         | 
| 38 | 
            +
                int2: :item_integer,
         | 
| 39 | 
            +
                a_float: :item_float
         | 
| 40 | 
            +
              }
         | 
| 41 | 
            +
            }
         | 
| 42 | 
            +
            ContentsCore.config( { components: conf[:cc_blocks] } )
         | 
| 43 | 
            +
            ```
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            Create the new view blocks: `app/views/contents_core/_block_custom.html.erb`
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            ```erb
         | 
| 48 | 
            +
            <% if local_assigns[:block] %>
         | 
| 49 | 
            +
              <% block = local_assigns[:block] %>
         | 
| 50 | 
            +
              <div <%= block.editable %>>
         | 
| 51 | 
            +
                1st number: <span class="num1"<%= block.props.integers[0].editable %>><%= block.props.integers[0] %></span>
         | 
| 52 | 
            +
                - 2nd number: <span class="num2"<%= block.props.integers[1].editable %>><%= block.props.integers[1] %></span><br/>
         | 
| 53 | 
            +
                A float: <span <%= block.props.float.editable %>><%= block.props.float %></span><br/>
         | 
| 54 | 
            +
              </div>
         | 
| 55 | 
            +
            <% end %>
         | 
| 56 | 
            +
            ```
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            ##### Images
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            To add support for images add CarrierWave gem to your Gemfile and execute: `rails generate uploader File` and mount it in the model *app/models/contents_core/item_file.rb*:
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            ```rb
         | 
| 63 | 
            +
            module ContentsCore
         | 
| 64 | 
            +
              class ItemFile < Item
         | 
| 65 | 
            +
                mount_uploader :data_file, ImageUploader
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                alias_attribute :data, :data_file
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                def editable
         | 
| 70 | 
            +
                  false
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                def init
         | 
| 74 | 
            +
                  self.data_file = File.open( Rails.root.join( 'public', 'images', 'original', 'missing.jpg' ) )
         | 
| 75 | 
            +
                  self
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                def self.type_name
         | 
| 79 | 
            +
                  'file'
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
            end
         | 
| 83 | 
            +
            ```
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            ##### Custom blocks
         | 
| 86 | 
            +
             | 
| 87 | 
            +
            To create a "free form" block just use: `Page.first.create_block :intro, name: 'IntroBlock', schema: { intro: :item_string, subtitle: :item_string }`
         | 
| 88 | 
            +
             | 
| 89 | 
            +
            ### Dev Notes
         | 
| 90 | 
            +
             | 
| 91 | 
            +
            ##### Structure
         | 
| 92 | 
            +
             | 
| 93 | 
            +
            - Including the Editable concern to a model will add `has_many :ec_blocks` relationship (the list of blocks attached to a container) and some utility methods
         | 
| 94 | 
            +
             | 
| 95 | 
            +
            - Block: an editable UI component (ex. a text with a title, a slider, a 3 column text widgets, etc.); built with a list of sub blocks (for nested components) and a list of items
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            - Item: a single piece of information (ex. a string, a text, a boolean, an integer, a file, etc.)
         | 
| 98 | 
            +
             | 
| 99 | 
            +
            ## Contributors
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            - [Mattia Roccoberton](http://blocknot.es) - creator, maintainer
         | 
    
        data/Rakefile
    ADDED
    
    | @@ -0,0 +1,36 @@ | |
| 1 | 
            +
            begin
         | 
| 2 | 
            +
              require 'bundler/setup'
         | 
| 3 | 
            +
            rescue LoadError
         | 
| 4 | 
            +
              puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
         | 
| 5 | 
            +
            end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            require 'rdoc/task'
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            RDoc::Task.new(:rdoc) do |rdoc|
         | 
| 10 | 
            +
              rdoc.rdoc_dir = 'rdoc'
         | 
| 11 | 
            +
              rdoc.title    = 'ContentsCore'
         | 
| 12 | 
            +
              rdoc.options << '--line-numbers'
         | 
| 13 | 
            +
              rdoc.rdoc_files.include('README.md')
         | 
| 14 | 
            +
              rdoc.rdoc_files.include('lib/**/*.rb')
         | 
| 15 | 
            +
            end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
         | 
| 18 | 
            +
            load 'rails/tasks/engine.rake'
         | 
| 19 | 
            +
             | 
| 20 | 
            +
             | 
| 21 | 
            +
            load 'rails/tasks/statistics.rake'
         | 
| 22 | 
            +
             | 
| 23 | 
            +
             | 
| 24 | 
            +
             | 
| 25 | 
            +
            require 'bundler/gem_tasks'
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            require 'rake/testtask'
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            Rake::TestTask.new(:test) do |t|
         | 
| 30 | 
            +
              t.libs << 'test'
         | 
| 31 | 
            +
              t.pattern = 'test/**/*_test.rb'
         | 
| 32 | 
            +
              t.verbose = false
         | 
| 33 | 
            +
            end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
             | 
| 36 | 
            +
            task default: :test
         | 
| @@ -0,0 +1,170 @@ | |
| 1 | 
            +
            module ContentsCore
         | 
| 2 | 
            +
              class Block < ApplicationRecord
         | 
| 3 | 
            +
                EMPTY_DATA = OpenStruct.new( { data: '' } )
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                # --- fields options ----------------------------------------------------- #
         | 
| 6 | 
            +
                serialize :options, JSON
         | 
| 7 | 
            +
                serialize :validations, JSON
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                # --- relations ---------------------------------------------------------- #
         | 
| 10 | 
            +
                belongs_to :parent, polymorphic: true
         | 
| 11 | 
            +
                has_many :cc_blocks, as: :parent, dependent: :destroy, foreign_key: 'parent_id', class_name: 'Block'
         | 
| 12 | 
            +
                has_many :items, dependent: :destroy
         | 
| 13 | 
            +
                accepts_nested_attributes_for :cc_blocks, allow_destroy: true
         | 
| 14 | 
            +
                accepts_nested_attributes_for :items
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                # --- hooks -------------------------------------------------------------- #
         | 
| 17 | 
            +
                before_create :on_before_create
         | 
| 18 | 
            +
                after_create :on_after_create
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                # --- scopes ------------------------------------------------------------- #
         | 
| 21 | 
            +
                default_scope { order( :position ) }
         | 
| 22 | 
            +
                scope :published, -> { where( published: true ) unless ContentsCore.editing }
         | 
| 23 | 
            +
                scope :with_nested, -> { includes( :items, cc_blocks: :items ) }
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                # --- validations -------------------------------------------------------- #
         | 
| 26 | 
            +
                validates_presence_of :block_type, :position
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                # --- misc --------------------------------------------------------------- #
         | 
| 29 | 
            +
                ## amoeba do
         | 
| 30 | 
            +
                ##   enable
         | 
| 31 | 
            +
                ##   # customize( lambda { |original_obj, new_obj|
         | 
| 32 | 
            +
                ##   #   original_obj.unit_pictures.each{|p| new_obj.unit_pictures.new(:data => File.open(p.data.file.path))}
         | 
| 33 | 
            +
                ##   # })
         | 
| 34 | 
            +
                ## end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                # after_validation :on_after_validation
         | 
| 37 | 
            +
                #
         | 
| 38 | 
            +
                # field :block_type, type: String, default: 'text'
         | 
| 39 | 
            +
                # field :name, type: String, default: ''
         | 
| 40 | 
            +
                # field :position, type: Integer, default: 0
         | 
| 41 | 
            +
                # field :published, type: Mongoid::Boolean, default: true
         | 
| 42 | 
            +
                # field :_init, type: Mongoid::Boolean, default: false
         | 
| 43 | 
            +
                #
         | 
| 44 | 
            +
                # embedded_in :parent, polymorphic: true
         | 
| 45 | 
            +
                #
         | 
| 46 | 
            +
                # embeds_many :cc_blocks, cascade_callbacks: true, order: :position.desc, class_name: 'ContentsCore::Block'
         | 
| 47 | 
            +
                # embeds_many :items, cascade_callbacks: true, class_name: 'ContentsCore::Item'
         | 
| 48 | 
            +
                #
         | 
| 49 | 
            +
                # accepts_nested_attributes_for :cc_blocks, allow_destroy: true
         | 
| 50 | 
            +
                # accepts_nested_attributes_for :items
         | 
| 51 | 
            +
                #
         | 
| 52 | 
            +
                # # scope :published, -> { where( published: true ) unless ApplicationController.edit_mode }
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def attr_id
         | 
| 55 | 
            +
                  "#{self.class.to_s.split('::').last}-#{self.id}"
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                def children_type
         | 
| 59 | 
            +
                  ContentsCore.config[:cc_blocks][block_type.to_sym][:children_type]
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def editable
         | 
| 63 | 
            +
                  ContentsCore.editing ? (
         | 
| 64 | 
            +
                    is_sub_block? ?
         | 
| 65 | 
            +
                    {
         | 
| 66 | 
            +
                      'data-ec-sub-block': self.id,
         | 
| 67 | 
            +
                      'data-ec-ct': self.block_type,
         | 
| 68 | 
            +
                      'data-ec-position': self.position,
         | 
| 69 | 
            +
                      'data-ec-pub': self.published
         | 
| 70 | 
            +
                    } :
         | 
| 71 | 
            +
                    {
         | 
| 72 | 
            +
                      'data-ec-block': self.id,
         | 
| 73 | 
            +
                      'data-ec-container': self.children_type,
         | 
| 74 | 
            +
                      'data-ec-ct': self.block_type,
         | 
| 75 | 
            +
                      'data-ec-pub': self.published
         | 
| 76 | 
            +
                    }
         | 
| 77 | 
            +
                  ).map { |k, v| "#{k}=\"#{v}\"" }.join( ' ' ).html_safe : ''
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                # Returns an item by name
         | 
| 81 | 
            +
                def get( name )
         | 
| 82 | 
            +
                  unless @_items
         | 
| 83 | 
            +
                    @_items = {}
         | 
| 84 | 
            +
                    items.each { |item| @_items[item.name] = item }
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
                  @_items[name]
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                def has_parent?
         | 
| 90 | 
            +
                  parent.present?
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                def has_children?
         | 
| 94 | 
            +
                  cc_blocks.exists?
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                def is_sub_block?
         | 
| 98 | 
            +
                  parent.present? && parent_type == 'ContentsCore::Block'
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                def on_after_create
         | 
| 102 | 
            +
                  # TODO: validates type before creation!
         | 
| 103 | 
            +
                  t = self.block_type.to_sym
         | 
| 104 | 
            +
                  Block::init_items( self, ContentsCore.config[:cc_blocks][t][:items] ) if Block::block_types.include?( t )
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                def on_before_create
         | 
| 108 | 
            +
                  if self.name.blank?
         | 
| 109 | 
            +
                    names = parent.cc_blocks.map &:name
         | 
| 110 | 
            +
                    i = 0
         | 
| 111 | 
            +
                    while( ( i += 1 ) < 1000 )  # Search an empty group
         | 
| 112 | 
            +
                      unless names.include? "#{block_type}-#{i}"
         | 
| 113 | 
            +
                        self.name = "#{block_type}-#{i}"
         | 
| 114 | 
            +
                        break
         | 
| 115 | 
            +
                      end
         | 
| 116 | 
            +
                    end
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
                end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                def props
         | 
| 121 | 
            +
                  pieces = {}
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                  Item::item_types.each do |type|
         | 
| 124 | 
            +
                    pieces[type.pluralize.to_sym] = []
         | 
| 125 | 
            +
                  end
         | 
| 126 | 
            +
                  items.each do |item|  # TODO: improve me
         | 
| 127 | 
            +
                    pieces[item.class.type_name.pluralize.to_sym].push item
         | 
| 128 | 
            +
                  end
         | 
| 129 | 
            +
                  Item::item_types.each do |type|
         | 
| 130 | 
            +
                    pieces[type.to_sym] = pieces[type.pluralize.to_sym].any? ? pieces[type.pluralize.to_sym].first : nil  # EMPTY_DATA - empty Item per sti class?
         | 
| 131 | 
            +
                  end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                  # pieces = {
         | 
| 134 | 
            +
                  #   images:   items.select { |item| item.type == ItemImage.to_s },
         | 
| 135 | 
            +
                  #   integers: items.select { |item| item.type == ItemInteger.to_s },
         | 
| 136 | 
            +
                  #   strings:  items.select { |item| item.type == ItemString.to_s },
         | 
| 137 | 
            +
                  #   texts:    items.select { |item| item.type == ItemText.to_s },
         | 
| 138 | 
            +
                  # }
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                  # pieces[:image]  = pieces[:images].any?  ? pieces[:images].first  : EMPTY_DATA
         | 
| 141 | 
            +
                  # pieces[:integers]  = pieces[:integers].any?  ? pieces[:integers].first  : EMPTY_DATA
         | 
| 142 | 
            +
                  # pieces[:string] = pieces[:strings].any? ? pieces[:strings].first : EMPTY_DATA
         | 
| 143 | 
            +
                  # pieces[:text]   = pieces[:texts].any?   ? pieces[:texts].first   : EMPTY_DATA
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                  OpenStruct.new( pieces )
         | 
| 146 | 
            +
                end
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                def self.block_types
         | 
| 149 | 
            +
                  @@block_types ||= ContentsCore.config[:cc_blocks].keys
         | 
| 150 | 
            +
                end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                def self.init_items( block, items )
         | 
| 153 | 
            +
                  items.each do |name, type|
         | 
| 154 | 
            +
                    t = type.to_sym
         | 
| 155 | 
            +
                    if type.to_s.start_with? 'item_'
         | 
| 156 | 
            +
                      c = 'ContentsCore::' + ActiveSupport::Inflector.camelize( t )
         | 
| 157 | 
            +
                      begin
         | 
| 158 | 
            +
                        model = c.constantize
         | 
| 159 | 
            +
                      rescue Exception => e
         | 
| 160 | 
            +
                        Rails.logger.error '[ERROR] ContentsCore - init_items: ' + e.message
         | 
| 161 | 
            +
                        model = false
         | 
| 162 | 
            +
                      end
         | 
| 163 | 
            +
                      block.items << model.new( name: name ).init if model
         | 
| 164 | 
            +
                    elsif Block::block_types.include? t.to_sym
         | 
| 165 | 
            +
                      block.cc_blocks << ( cmp = Block.new( block_type: t, name: name ) )
         | 
| 166 | 
            +
                    end
         | 
| 167 | 
            +
                  end if items
         | 
| 168 | 
            +
                end
         | 
| 169 | 
            +
              end
         | 
| 170 | 
            +
            end
         | 
| @@ -0,0 +1,50 @@ | |
| 1 | 
            +
            module ContentsCore
         | 
| 2 | 
            +
              class Item < ApplicationRecord
         | 
| 3 | 
            +
                # field :data, type: String
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                # embedded_in :cc_blocks
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                belongs_to :block
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def attr_id
         | 
| 10 | 
            +
                  "#{self.class_name}-#{self.id}"
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def class_name
         | 
| 14 | 
            +
                  self.class.to_s.split('::').last
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def editable
         | 
| 18 | 
            +
                  ContentsCore.editing ? " data-ec-item=\"#{self.id}\" data-ec-input=\"#{self.opt_input}\" data-ec-type=\"#{self.class_name}\"".html_safe : ''
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def opt_input
         | 
| 22 | 
            +
                  if self.block.options[self.name] && self.block.options[self.name]['input']
         | 
| 23 | 
            +
                    self.block.options[self.name]['input'].to_s
         | 
| 24 | 
            +
                  elsif config[:input]
         | 
| 25 | 
            +
                    config[:input].to_s
         | 
| 26 | 
            +
                  else
         | 
| 27 | 
            +
                    ''
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def to_s
         | 
| 32 | 
            +
                  self.data
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def update_data( value )
         | 
| 36 | 
            +
                  self.data = value
         | 
| 37 | 
            +
                  self.save
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def self.item_types
         | 
| 41 | 
            +
                  @@item_types ||= ContentsCore.config[:items].keys.map &:to_s
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              protected
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def config
         | 
| 47 | 
            +
                  @config ||= ContentsCore.config[:items][self.class::type_name.to_sym] ? ContentsCore.config[:items][self.class::type_name.to_sym] : {}
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
            end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            module ContentsCore
         | 
| 2 | 
            +
              class ItemBoolean < Item
         | 
| 3 | 
            +
                alias_attribute :data, :data_boolean
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def init
         | 
| 6 | 
            +
                  self.data = 0
         | 
| 7 | 
            +
                  self
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def update_data( value )
         | 
| 11 | 
            +
                  self.data = ( value == 'true' ) ? 1 : 0
         | 
| 12 | 
            +
                  self.save
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def to_s
         | 
| 16 | 
            +
                  self.data > 0 ? 'true' : 'false'
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def self.type_name
         | 
| 20 | 
            +
                  'boolean'
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,46 @@ | |
| 1 | 
            +
            module ContentsCore
         | 
| 2 | 
            +
              class ItemFile < Item
         | 
| 3 | 
            +
                # has_attached_file :data_string
         | 
| 4 | 
            +
                # validates_attachment_content_type :data_string, content_type: ['image/jpg', 'image/jpeg', 'image/png', 'image/gif']
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                # include Mongoid::Paperclip
         | 
| 7 | 
            +
                # has_mongoid_attached_file :data
         | 
| 8 | 
            +
                # validates_attachment_content_type :data, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                # mount_uploader :data_file, ::FileUploader
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                alias_attribute :data, :data_file
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def editable
         | 
| 15 | 
            +
                  ContentsCore.editing ? { 'data-ec-item': self.id, 'data-ec-input': self.opt_input, 'data-ec-type': self.class_name, 'data-ec-block': self.block_id } : {}
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def init
         | 
| 19 | 
            +
                  # self.data_file = File.open( ContentsCore::Engine.root.join( 'lib', 'data', 'img1.jpg' ) )
         | 
| 20 | 
            +
                  self
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def self.type_name
         | 
| 24 | 
            +
                  'file'
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                # before_validation :on_before_validation
         | 
| 28 | 
            +
                #
         | 
| 29 | 
            +
                # def on_before_validation
         | 
| 30 | 
            +
                #   self.data = File.open( 'rails/editable_components_test/public/img/img1.jpg' )
         | 
| 31 | 
            +
                #   # binding.pry
         | 
| 32 | 
            +
                # end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                # before_save :on_before_save
         | 
| 35 | 
            +
                # before_validation :on_before_validation
         | 
| 36 | 
            +
                # before_create :on_before_create
         | 
| 37 | 
            +
                # before_update :on_before_update
         | 
| 38 | 
            +
                # before_upsert :on_before_upsert
         | 
| 39 | 
            +
                #
         | 
| 40 | 
            +
                # def on_before_save; p '>>> before_save'; end
         | 
| 41 | 
            +
                # def on_before_validation; p '>>> before_validation'; end
         | 
| 42 | 
            +
                # def on_before_create; p '>>> before_create'; end
         | 
| 43 | 
            +
                # def on_before_update; p '>>> before_update'; end
         | 
| 44 | 
            +
                # def on_before_upsert; p '>>> before_upsert'; end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
            end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            module ContentsCore
         | 
| 2 | 
            +
              class ItemFloat < Item
         | 
| 3 | 
            +
                alias_attribute :data, :data_float
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def init
         | 
| 6 | 
            +
                  self.data = 0
         | 
| 7 | 
            +
                  self
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def update_data( value )
         | 
| 11 | 
            +
                  self.data = value.to_f
         | 
| 12 | 
            +
                  self.save
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def to_s
         | 
| 16 | 
            +
                  self.data.to_s
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def self.type_name
         | 
| 20 | 
            +
                  'float'
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            module ContentsCore
         | 
| 2 | 
            +
              class ItemInteger < Item
         | 
| 3 | 
            +
                alias_attribute :data, :data_integer
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def init
         | 
| 6 | 
            +
                  self.data = 0
         | 
| 7 | 
            +
                  self
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def update_data( value )
         | 
| 11 | 
            +
                  self.data = value.to_i
         | 
| 12 | 
            +
                  self.save
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def to_s
         | 
| 16 | 
            +
                  self.data.to_s
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def self.type_name
         | 
| 20 | 
            +
                  'integer'
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            module ContentsCore
         | 
| 2 | 
            +
              class ItemString < Item
         | 
| 3 | 
            +
                alias_attribute :data, :data_string
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                validate :on_validate
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def init
         | 
| 8 | 
            +
                  self.data = self.name.gsub( /-/, ' ' ).humanize
         | 
| 9 | 
            +
                  self
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def on_validate
         | 
| 13 | 
            +
                  if self.block.validations[self.name]
         | 
| 14 | 
            +
                    if self.block.validations[self.name] == 'required'
         | 
| 15 | 
            +
                      self.errors.add( :base, "#{self.name} is required" ) if self.data_string.blank?
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def update_data( value )
         | 
| 21 | 
            +
                  self.data = ActionController::Base.helpers.sanitize( value, tags: [] )
         | 
| 22 | 
            +
                  self.save
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def self.type_name
         | 
| 26 | 
            +
                  'string'
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            module ContentsCore
         | 
| 2 | 
            +
              class ItemText < Item
         | 
| 3 | 
            +
                alias_attribute :data, :data_text
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def init
         | 
| 6 | 
            +
                  self.data = self.name.gsub( /-/, ' ' ).humanize
         | 
| 7 | 
            +
                  self
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def update_data( value )
         | 
| 11 | 
            +
                  self.data = ActionController::Base.helpers.sanitize( CGI.unescapeHTML( value ) )
         | 
| 12 | 
            +
                  self.save
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def self.type_name
         | 
| 16 | 
            +
                  'text'
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,73 @@ | |
| 1 | 
            +
            module ContentsCore
         | 
| 2 | 
            +
              @@editing = false
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              @@config = {
         | 
| 5 | 
            +
                cc_blocks: {
         | 
| 6 | 
            +
                  multi_text: {
         | 
| 7 | 
            +
                    children_type: :text,
         | 
| 8 | 
            +
                    name: 'Multi columns block',
         | 
| 9 | 
            +
                    items: {
         | 
| 10 | 
            +
                      column: :text
         | 
| 11 | 
            +
                    }
         | 
| 12 | 
            +
                  },
         | 
| 13 | 
            +
                  text: {
         | 
| 14 | 
            +
                    name: 'Text block',
         | 
| 15 | 
            +
                    items: {
         | 
| 16 | 
            +
                      title: :item_string,
         | 
| 17 | 
            +
                      content: :item_text
         | 
| 18 | 
            +
                    }
         | 
| 19 | 
            +
                  },
         | 
| 20 | 
            +
                },
         | 
| 21 | 
            +
                items: {
         | 
| 22 | 
            +
                  boolean: {},
         | 
| 23 | 
            +
                  datetime: {},
         | 
| 24 | 
            +
                  float: {},
         | 
| 25 | 
            +
                  hash: {},
         | 
| 26 | 
            +
                  file: {
         | 
| 27 | 
            +
                    input: :file_image
         | 
| 28 | 
            +
                  },
         | 
| 29 | 
            +
                  integer: {},
         | 
| 30 | 
            +
                  string: {},
         | 
| 31 | 
            +
                  text: {
         | 
| 32 | 
            +
                    input: :html
         | 
| 33 | 
            +
                  },
         | 
| 34 | 
            +
                }
         | 
| 35 | 
            +
              }
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              if defined? CarrierWave
         | 
| 38 | 
            +
                @@config[:cc_blocks].merge!({
         | 
| 39 | 
            +
                  image: {
         | 
| 40 | 
            +
                    name: 'Image block',
         | 
| 41 | 
            +
                    items: {
         | 
| 42 | 
            +
                      img: :item_file
         | 
| 43 | 
            +
                    }
         | 
| 44 | 
            +
                  },
         | 
| 45 | 
            +
                  slide: {
         | 
| 46 | 
            +
                    name: 'Slide block',
         | 
| 47 | 
            +
                    items: {
         | 
| 48 | 
            +
                      img: :item_file,
         | 
| 49 | 
            +
                      title: :item_string
         | 
| 50 | 
            +
                    }
         | 
| 51 | 
            +
                  },
         | 
| 52 | 
            +
                  slider: {
         | 
| 53 | 
            +
                    children_type: :slide,
         | 
| 54 | 
            +
                    name: 'Slider block',
         | 
| 55 | 
            +
                    items: {
         | 
| 56 | 
            +
                      slide: :slide
         | 
| 57 | 
            +
                    }
         | 
| 58 | 
            +
                  },
         | 
| 59 | 
            +
                  text_with_image: {
         | 
| 60 | 
            +
                    name: 'Text with image block',
         | 
| 61 | 
            +
                    items: {
         | 
| 62 | 
            +
                      img: :item_file,
         | 
| 63 | 
            +
                      title: :item_string,
         | 
| 64 | 
            +
                      content: :item_text
         | 
| 65 | 
            +
                    }
         | 
| 66 | 
            +
                  },
         | 
| 67 | 
            +
                })
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                # ItemImage.class_eval do
         | 
| 70 | 
            +
                #   mount_uploader :data, ImageUploader
         | 
| 71 | 
            +
                # end
         | 
| 72 | 
            +
              end
         | 
| 73 | 
            +
            end
         | 
    
        data/config/routes.rb
    ADDED
    
    
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            class CreateContentsCoreBlocks < ActiveRecord::Migration[5.0]
         | 
| 2 | 
            +
              def change
         | 
| 3 | 
            +
                create_table :contents_core_blocks do |t|
         | 
| 4 | 
            +
                  t.string :block_type, null: false, default: 'text'
         | 
| 5 | 
            +
                  t.integer :version, null: false, default: 0
         | 
| 6 | 
            +
                  t.string :name, null: false, default: ''
         | 
| 7 | 
            +
                  t.integer :position, null: false, default: 0
         | 
| 8 | 
            +
                  t.boolean :published, null: false, default: true
         | 
| 9 | 
            +
                  t.string :options, null: false, default: '{}'
         | 
| 10 | 
            +
                  t.string :validations, null: false, default: '{}'
         | 
| 11 | 
            +
                  t.integer :parent_id
         | 
| 12 | 
            +
                  t.string :parent_type
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                add_index :contents_core_blocks, [:parent_id, :parent_type]
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| @@ -0,0 +1,11 @@ | |
| 1 | 
            +
            class CreateContentsCoreItems < ActiveRecord::Migration[5.0]
         | 
| 2 | 
            +
              def change
         | 
| 3 | 
            +
                create_table :contents_core_items do |t|
         | 
| 4 | 
            +
                  t.string :type
         | 
| 5 | 
            +
                  t.string :name, null: false, default: 'data'
         | 
| 6 | 
            +
                  t.integer :block_id
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                add_index :contents_core_items, :block_id
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
            end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            class AddExtraItems < ActiveRecord::Migration[5.0]
         | 
| 2 | 
            +
              def change
         | 
| 3 | 
            +
                add_column :contents_core_items, :data_boolean, :boolean
         | 
| 4 | 
            +
                add_column :contents_core_items, :data_datetime, :datetime
         | 
| 5 | 
            +
                add_column :contents_core_items, :data_file, :string  # , null: false, default: ''
         | 
| 6 | 
            +
                add_column :contents_core_items, :data_float, :float
         | 
| 7 | 
            +
                add_column :contents_core_items, :data_hash, :string  # , null: false, default: ''
         | 
| 8 | 
            +
                add_column :contents_core_items, :data_integer, :integer
         | 
| 9 | 
            +
                add_column :contents_core_items, :data_string, :string  # , null: false, default: ''
         | 
| 10 | 
            +
                add_column :contents_core_items, :data_text, :text
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
| @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            require 'contents_core/blocks'
         | 
| 2 | 
            +
            require 'contents_core/engine'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module ContentsCore
         | 
| 5 | 
            +
              def self.config( options = {} )
         | 
| 6 | 
            +
                @@config.merge! options
         | 
| 7 | 
            +
                @@config
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def self.editing( editing = nil )
         | 
| 11 | 
            +
                @@editing = editing unless editing.nil?
         | 
| 12 | 
            +
                @@editing
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
            end
         | 
| @@ -0,0 +1,34 @@ | |
| 1 | 
            +
            module ContentsCore
         | 
| 2 | 
            +
              module Blocks
         | 
| 3 | 
            +
                extend ActiveSupport::Concern
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                included do
         | 
| 6 | 
            +
                  # embeds_many :cc_blocks, as: :parent, cascade_callbacks: true, order: :position.desc, class_name: 'ContentsCore::Block'
         | 
| 7 | 
            +
                  has_many :cc_blocks, as: :parent, dependent: :destroy, foreign_key: 'parent_id', class_name: Block.to_s
         | 
| 8 | 
            +
                  accepts_nested_attributes_for :cc_blocks, allow_destroy: true
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def create_block( type = :text, params = {} )
         | 
| 11 | 
            +
                    block = Block.new( block_type: type )
         | 
| 12 | 
            +
                    block.name = params[:name] if params[:name]
         | 
| 13 | 
            +
                    block.options = params[:options] if params[:options]
         | 
| 14 | 
            +
                    block.validations = params[:validations] if params[:validations]
         | 
| 15 | 
            +
                    cc_blocks << block
         | 
| 16 | 
            +
                    Block::init_items block, params[:schema] if params[:schema]
         | 
| 17 | 
            +
                    block
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  def current_blocks( version = 0 )
         | 
| 21 | 
            +
                    return @current_blocks if @current_blocks
         | 
| 22 | 
            +
                    version = 0 unless ContentsCore.editing  # no admin = only current version
         | 
| 23 | 
            +
                    @current_blocks = cc_blocks.where( version: version.to_i ).with_nested.published
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def get_block( name, version = 0 )
         | 
| 27 | 
            +
                    current_blocks( version ).each do |block|
         | 
| 28 | 
            +
                      return block if block.name == name
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
                    nil
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,83 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: contents_core
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.1.0
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Mat
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2017-07-08 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: rails
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - "~>"
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '5'
         | 
| 20 | 
            +
              type: :runtime
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - "~>"
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '5'
         | 
| 27 | 
            +
            description: A Rails gem which offer a simple structure to manage contents in a flexible
         | 
| 28 | 
            +
              way
         | 
| 29 | 
            +
            email:
         | 
| 30 | 
            +
            - mat@blocknot.es
         | 
| 31 | 
            +
            executables: []
         | 
| 32 | 
            +
            extensions: []
         | 
| 33 | 
            +
            extra_rdoc_files: []
         | 
| 34 | 
            +
            files:
         | 
| 35 | 
            +
            - MIT-LICENSE
         | 
| 36 | 
            +
            - README.md
         | 
| 37 | 
            +
            - Rakefile
         | 
| 38 | 
            +
            - app/models/contents_core/application_record.rb
         | 
| 39 | 
            +
            - app/models/contents_core/block.rb
         | 
| 40 | 
            +
            - app/models/contents_core/item.rb
         | 
| 41 | 
            +
            - app/models/contents_core/item_boolean.rb
         | 
| 42 | 
            +
            - app/models/contents_core/item_datetime.rb
         | 
| 43 | 
            +
            - app/models/contents_core/item_file.rb
         | 
| 44 | 
            +
            - app/models/contents_core/item_float.rb
         | 
| 45 | 
            +
            - app/models/contents_core/item_hash.rb
         | 
| 46 | 
            +
            - app/models/contents_core/item_integer.rb
         | 
| 47 | 
            +
            - app/models/contents_core/item_string.rb
         | 
| 48 | 
            +
            - app/models/contents_core/item_text.rb
         | 
| 49 | 
            +
            - config/initializers/contents_core.rb
         | 
| 50 | 
            +
            - config/routes.rb
         | 
| 51 | 
            +
            - db/migrate/20170414173603_create_contents_core_blocks.rb
         | 
| 52 | 
            +
            - db/migrate/20170414173610_create_contents_core_items.rb
         | 
| 53 | 
            +
            - db/migrate/20170414173611_add_extra_items.rb
         | 
| 54 | 
            +
            - lib/contents_core.rb
         | 
| 55 | 
            +
            - lib/contents_core/blocks.rb
         | 
| 56 | 
            +
            - lib/contents_core/engine.rb
         | 
| 57 | 
            +
            - lib/contents_core/version.rb
         | 
| 58 | 
            +
            - lib/tasks/contents_core_tasks.rake
         | 
| 59 | 
            +
            homepage: https://github.com/blocknotes/contents_core
         | 
| 60 | 
            +
            licenses:
         | 
| 61 | 
            +
            - MIT
         | 
| 62 | 
            +
            metadata: {}
         | 
| 63 | 
            +
            post_install_message: 
         | 
| 64 | 
            +
            rdoc_options: []
         | 
| 65 | 
            +
            require_paths:
         | 
| 66 | 
            +
            - lib
         | 
| 67 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 68 | 
            +
              requirements:
         | 
| 69 | 
            +
              - - ">="
         | 
| 70 | 
            +
                - !ruby/object:Gem::Version
         | 
| 71 | 
            +
                  version: '0'
         | 
| 72 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 73 | 
            +
              requirements:
         | 
| 74 | 
            +
              - - ">="
         | 
| 75 | 
            +
                - !ruby/object:Gem::Version
         | 
| 76 | 
            +
                  version: '0'
         | 
| 77 | 
            +
            requirements: []
         | 
| 78 | 
            +
            rubyforge_project: 
         | 
| 79 | 
            +
            rubygems_version: 2.5.2
         | 
| 80 | 
            +
            signing_key: 
         | 
| 81 | 
            +
            specification_version: 4
         | 
| 82 | 
            +
            summary: Flexible contents structure for Rails
         | 
| 83 | 
            +
            test_files: []
         |