arbre-1.2.1/ 0000755 0001750 0001750 00000000000 13523740213 012142 5 ustar samyak samyak arbre-1.2.1/LICENSE 0000644 0001750 0001750 00000002035 13523740213 013147 0 ustar samyak samyak Copyright (c) 2013 Greg Bell
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
arbre-1.2.1/.travis.yml 0000644 0001750 0001750 00000000347 13523740213 014257 0 ustar samyak samyak language: ruby
sudo: false
before_install:
- gem update --system 3.0.3
- gem install bundler:2.0.1
rvm:
- 2.3.8
- 2.4.5
- 2.5.5
- 2.6.2
- jruby-9.1.17.0
- jruby-9.2.6.0
branches:
only:
- master
cache: bundler
arbre-1.2.1/.rubocop.yml 0000644 0001750 0001750 00000000267 13523740213 014421 0 ustar samyak samyak ---
AllCops:
DisabledByDefault: true
DisplayCopNames: true
DisplayStyleGuide: true
TargetRubyVersion: 2.3
Metrics:
Enabled: false
Layout/IndentHeredoc:
Enabled: true
arbre-1.2.1/tasks/ 0000755 0001750 0001750 00000000000 13523740213 013267 5 ustar samyak samyak arbre-1.2.1/tasks/release.rake 0000644 0001750 0001750 00000000201 13523740213 015544 0 ustar samyak samyak require "chandler/tasks"
#
# Add chandler as a prerequisite for `rake release`
#
task "release:rubygem_push" => "chandler:push"
arbre-1.2.1/tasks/lint.rake 0000644 0001750 0001750 00000002344 13523740213 015104 0 ustar samyak samyak require "open3"
#
# Common stuff for a linter
#
module LinterMixin
def run
offenses = []
applicable_files.each do |file|
if clean?(file)
print "."
else
offenses << file
print "F"
end
end
print "\n"
return if offenses.empty?
raise failure_message_for(offenses)
end
private
def applicable_files
Open3.capture2("git grep -Il ''")[0].split
end
def failure_message_for(offenses)
msg = "#{self.class.name} detected offenses. "
msg += if respond_to?(:fixing_cmd)
"Run `#{fixing_cmd(offenses)}` to fix them."
else
"Affected files: #{offenses.join(' ')}"
end
msg
end
end
#
# Checks trailing new lines in files
#
class MissingTrailingCarriageReturn
include LinterMixin
def clean?(file)
File.read(file) =~ /\n\Z/m
end
end
require 'rubocop/rake_task'
RuboCop::RakeTask.new
desc "Lints ActiveAdmin code base"
task lint: ["rubocop", "lint:missing_trailing_carriage_return"]
namespace :lint do
desc "Check for missing trailing new lines"
task :missing_trailing_carriage_return do
puts "Checking for missing trailing carriage returns..."
MissingTrailingCarriageReturn.new.run
end
end
arbre-1.2.1/lib/ 0000755 0001750 0001750 00000000000 13523740213 012710 5 ustar samyak samyak arbre-1.2.1/lib/arbre.rb 0000644 0001750 0001750 00000000727 13523740213 014336 0 ustar samyak samyak require 'active_support/core_ext/string/output_safety'
require 'active_support/hash_with_indifferent_access'
require 'active_support/inflector'
module Arbre
end
require 'arbre/element'
require 'arbre/context'
require 'arbre/html/attributes'
require 'arbre/html/class_list'
require 'arbre/html/tag'
require 'arbre/html/text_node'
require 'arbre/html/document'
require 'arbre/html/html5_elements'
require 'arbre/component'
if defined?(Rails)
require 'arbre/rails'
end
arbre-1.2.1/lib/arbre/ 0000755 0001750 0001750 00000000000 13523740213 014003 5 ustar samyak samyak arbre-1.2.1/lib/arbre/element/ 0000755 0001750 0001750 00000000000 13523740213 015434 5 ustar samyak samyak arbre-1.2.1/lib/arbre/element/builder_methods.rb 0000644 0001750 0001750 00000004225 13523740213 021135 0 ustar samyak samyak module Arbre
class Element
module BuilderMethods
def self.included(klass)
klass.extend ClassMethods
end
module ClassMethods
def builder_method(method_name)
BuilderMethods.class_eval <<-EOF, __FILE__, __LINE__
def #{method_name}(*args, &block)
insert_tag ::#{self.name}, *args, &block
end
EOF
end
end
def build_tag(klass, *args, &block)
tag = klass.new(arbre_context)
tag.parent = current_arbre_element
with_current_arbre_element tag do
if block_given? && block.arity > 0
tag.build(*args, &block)
else
tag.build(*args)
append_return_block(yield) if block_given?
end
end
tag
end
def insert_tag(klass, *args, &block)
tag = build_tag(klass, *args, &block)
current_arbre_element.add_child(tag)
tag
end
def current_arbre_element
arbre_context.current_arbre_element
end
def with_current_arbre_element(tag, &block)
arbre_context.with_current_arbre_element(tag, &block)
end
alias_method :within, :with_current_arbre_element
private
# Appends the value to the current DOM element if there are no
# existing DOM Children and it responds to #to_s
def append_return_block(tag)
return nil if current_arbre_element.children?
if appendable_tag?(tag)
current_arbre_element << Arbre::HTML::TextNode.from_string(tag.to_s)
end
end
# Returns true if the object should be converted into a text node
# and appended into the DOM.
def appendable_tag?(tag)
# Array.new.to_s prints out an empty array ("[]"). In
# Arbre, we append the return value of blocks to the output, which
# can cause empty arrays to show up within the output. To get
# around this, we check if the object responds to #empty?
if tag.respond_to?(:empty?) && tag.empty?
false
else
!tag.is_a?(Arbre::Element) && tag.respond_to?(:to_s)
end
end
end
end
end
arbre-1.2.1/lib/arbre/element/proxy.rb 0000644 0001750 0001750 00000001103 13523740213 017135 0 ustar samyak samyak module Arbre
class Element
class Proxy < BasicObject
undef_method :==
undef_method :equal?
def initialize(element)
@element = element
end
def respond_to?(method, include_all = false)
if method.to_s == 'to_ary'
false
else
super || @element.respond_to?(method, include_all)
end
end
def method_missing(method, *args, &block)
if method.to_s == 'to_ary'
super
else
@element.__send__ method, *args, &block
end
end
end
end
end
arbre-1.2.1/lib/arbre/component.rb 0000644 0001750 0001750 00000000566 13523740213 016341 0 ustar samyak samyak module Arbre
class Component < Arbre::HTML::Div
# By default components render a div
def tag_name
'div'
end
def initialize(*)
super
add_class default_class_name
end
protected
# By default, add a css class named after the ruby class
def default_class_name
self.class.name.demodulize.underscore
end
end
end
arbre-1.2.1/lib/arbre/rails.rb 0000644 0001750 0001750 00000000232 13523740213 015437 0 ustar samyak samyak require 'arbre/rails/template_handler'
require 'arbre/rails/forms'
require 'arbre/rails/rendering'
Arbre::Element.send :include, Arbre::Rails::Rendering
arbre-1.2.1/lib/arbre/html/ 0000755 0001750 0001750 00000000000 13523740213 014747 5 ustar samyak samyak arbre-1.2.1/lib/arbre/html/text_node.rb 0000644 0001750 0001750 00000001074 13523740213 017267 0 ustar samyak samyak require 'erb'
module Arbre
module HTML
class TextNode < Element
builder_method :text_node
# Builds a text node from a string
def self.from_string(string)
node = new
node.build(string)
node
end
def add_child(*args)
raise "TextNodes do not have children"
end
def build(string)
@content = string
end
def class_list
[]
end
def tag_name
nil
end
def to_s
ERB::Util.html_escape(@content.to_s)
end
end
end
end
arbre-1.2.1/lib/arbre/html/class_list.rb 0000644 0001750 0001750 00000000646 13523740213 017442 0 ustar samyak samyak require 'set'
module Arbre
module HTML
# Holds a set of classes
class ClassList < Set
def self.build_from_string(class_names)
new.add(class_names)
end
def add(class_names)
class_names.to_s.split(" ").each do |class_name|
super(class_name)
end
self
end
alias :<< :add
def to_s
to_a.join(" ")
end
end
end
end
arbre-1.2.1/lib/arbre/html/tag.rb 0000644 0001750 0001750 00000010361 13523740213 016050 0 ustar samyak samyak require 'erb'
module Arbre
module HTML
class Tag < Element
attr_reader :attributes
# See: http://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements
SELF_CLOSING_ELEMENTS = [ :area, :base, :br, :col, :embed, :hr, :img, :input, :keygen, :link,
:menuitem, :meta, :param, :source, :track, :wbr ]
def initialize(*)
super
@attributes = Attributes.new
end
def build(*args)
super
attributes = extract_arguments(args)
self.content = args.first if args.first
for_value = attributes[:for]
unless for_value.is_a?(String) || for_value.is_a?(Symbol)
set_for_attribute(attributes.delete(:for))
end
attributes.each do |key, value|
set_attribute(key, value)
end
end
def extract_arguments(args)
if args.last.is_a?(Hash)
args.pop
else
{}
end
end
def set_attribute(name, value)
@attributes[name.to_sym] = value
end
def get_attribute(name)
@attributes[name.to_sym]
end
alias :attr :get_attribute
def has_attribute?(name)
@attributes.has_key?(name.to_sym)
end
def remove_attribute(name)
@attributes.delete(name.to_sym)
end
def id
get_attribute(:id)
end
# Generates and id for the object if it doesn't exist already
def id!
return id if id
self.id = object_id.to_s
id
end
def id=(id)
set_attribute(:id, id)
end
def add_class(class_names)
class_list.add class_names
end
def remove_class(class_names)
class_list.delete(class_names)
end
# Returns a string of classes
def class_names
class_list.to_s
end
def class_list
list = get_attribute(:class)
case list
when ClassList
list
when String
set_attribute(:class, ClassList.build_from_string(list))
else
set_attribute(:class, ClassList.new)
end
end
def to_s
indent(opening_tag, content, closing_tag).html_safe
end
private
def opening_tag
"<#{tag_name}#{attributes_html}>"
end
def closing_tag
"#{tag_name}>"
end
INDENT_SIZE = 2
def indent(open_tag, child_content, close_tag)
spaces = ' ' * indent_level * INDENT_SIZE
html = ""
if no_child? || child_is_text?
if self_closing_tag?
html << spaces << open_tag.sub( />$/, '/>' )
else
# one line
html << spaces << open_tag << child_content << close_tag
end
else
# multiple lines
html << spaces << open_tag << "\n"
html << child_content # the child takes care of its own spaces
html << spaces << close_tag
end
html << "\n"
html
end
def self_closing_tag?
SELF_CLOSING_ELEMENTS.include?(tag_name.to_sym)
end
def no_child?
children.empty?
end
def child_is_text?
children.size == 1 && children.first.is_a?(TextNode)
end
def attributes_html
" #{attributes}" if attributes.any?
end
def set_for_attribute(record)
return unless record
# set_attribute :id, ActionController::RecordIdentifier.dom_id(record, default_id_for_prefix)
# add_class ActionController::RecordIdentifier.dom_class(record)
set_attribute :id, dom_id_for(record)
add_class dom_class_name_for(record)
end
def dom_class_name_for(record)
if record.class.respond_to?(:model_name)
record.class.model_name.singular
else
record.class.name.underscore.gsub("/", "_")
end
end
def dom_id_for(record)
id = if record.respond_to?(:to_key)
record.to_key
elsif record.respond_to?(:id)
record.id
else
record.object_id
end
[default_id_for_prefix, dom_class_name_for(record), id].compact.join("_")
end
def default_id_for_prefix
nil
end
end
end
end
arbre-1.2.1/lib/arbre/html/document.rb 0000644 0001750 0001750 00000001107 13523740213 017111 0 ustar samyak samyak module Arbre
module HTML
class Document < Tag
def build(*args)
super
build_head
build_body
end
def document
self
end
def tag_name
'html'
end
def doctype
''.html_safe
end
def to_s
doctype + super
end
protected
def build_head
@head = head do
meta :"http-equiv" => "Content-type", content: "text/html; charset=utf-8"
end
end
def build_body
@body = body
end
end
end
end
arbre-1.2.1/lib/arbre/html/html5_elements.rb 0000644 0001750 0001750 00000003217 13523740213 020224 0 ustar samyak samyak module Arbre
module HTML
AUTO_BUILD_ELEMENTS = [ :a, :abbr, :address, :area, :article, :aside, :audio, :b, :base,
:bdo, :blockquote, :body, :br, :button, :canvas, :caption, :cite,
:code, :col, :colgroup, :command, :datalist, :dd, :del, :details,
:dfn, :div, :dl, :dt, :em, :embed, :fieldset, :figcaption, :figure,
:footer, :form, :h1, :h2, :h3, :h4, :h5, :h6, :head, :header, :hgroup,
:hr, :html, :i, :iframe, :img, :input, :ins, :keygen, :kbd, :label,
:legend, :li, :link, :map, :mark, :menu, :menuitem, :meta, :meter, :nav, :noscript,
:object, :ol, :optgroup, :option, :output, :param, :pre, :progress, :q,
:s, :samp, :script, :section, :select, :small, :source, :span,
:strong, :style, :sub, :summary, :sup, :svg, :table, :tbody, :td,
:textarea, :tfoot, :th, :thead, :time, :title, :tr, :track, :ul, :var, :video, :wbr ]
HTML5_ELEMENTS = [ :p ] + AUTO_BUILD_ELEMENTS
AUTO_BUILD_ELEMENTS.each do |name|
class_eval <<-EOF
class #{name.to_s.capitalize} < Tag
builder_method :#{name}
end
EOF
end
class P < Tag
builder_method :para
end
class Table < Tag
def initialize(*)
super
set_table_tag_defaults
end
protected
# Set some good defaults for tables
def set_table_tag_defaults
set_attribute :border, 0
set_attribute :cellspacing, 0
set_attribute :cellpadding, 0
end
end
end
end
arbre-1.2.1/lib/arbre/html/attributes.rb 0000644 0001750 0001750 00000000774 13523740213 017472 0 ustar samyak samyak module Arbre
module HTML
class Attributes < Hash
def to_s
map do |name, value|
next if value_empty?(value)
"#{html_escape(name)}=\"#{html_escape(value)}\""
end.compact.join ' '
end
def any?
super{ |k,v| !value_empty?(v) }
end
protected
def value_empty?(value)
value.respond_to?(:empty?) ? value.empty? : !value
end
def html_escape(s)
ERB::Util.html_escape(s)
end
end
end
end
arbre-1.2.1/lib/arbre/context.rb 0000644 0001750 0001750 00000005436 13523740213 016024 0 ustar samyak samyak require 'arbre/element'
module Arbre
# The Arbre::Context class is the frontend for using Arbre.
#
# The simplest example possible:
#
# html = Arbre::Context.new do
# h1 "Hello World"
# end
#
# html.to_s #=> "
Hello World
"
#
# The contents of the block are instance eval'd within the Context
# object. This means that you lose context to the outside world from
# within the block. To pass local variables into the Context, use the
# assigns param.
#
# html = Arbre::Context.new({one: 1}) do
# h1 "Your number #{one}"
# end
#
# html.to_s #=> "Your number 1"
#
class Context < Element
# Initialize a new Arbre::Context
#
# @param [Hash] assigns A hash of objecs that you would like to be
# availble as local variables within the Context
#
# @param [Object] helpers An object that has methods on it which will become
# instance methods within the context.
#
# @yield [] The block that will get instance eval'd in the context
def initialize(assigns = {}, helpers = nil, &block)
assigns = assigns || {}
@_assigns = assigns.symbolize_keys
@_helpers = helpers
@_current_arbre_element_buffer = [self]
super(self)
instance_eval(&block) if block_given?
end
def arbre_context
self
end
def assigns
@_assigns
end
def helpers
@_helpers
end
def indent_level
# A context does not increment the indent_level
super - 1
end
def bytesize
cached_html.bytesize
end
alias :length :bytesize
def respond_to_missing?(method, include_all)
super || cached_html.respond_to?(method, include_all)
end
# Webservers treat Arbre::Context as a string. We override
# method_missing to delegate to the string representation
# of the html.
def method_missing(method, *args, &block)
if cached_html.respond_to? method
cached_html.send method, *args, &block
else
super
end
end
def current_arbre_element
@_current_arbre_element_buffer.last
end
def with_current_arbre_element(tag)
raise ArgumentError, "Can't be in the context of nil. #{@_current_arbre_element_buffer.inspect}" unless tag
@_current_arbre_element_buffer.push tag
yield
@_current_arbre_element_buffer.pop
end
alias_method :within, :with_current_arbre_element
private
# Caches the rendered HTML so that we don't re-render just to
# get the content lenght or to delegate a method to the HTML
def cached_html
if defined?(@cached_html)
@cached_html
else
html = to_s
@cached_html = html if html.length > 0
html
end
end
end
end
arbre-1.2.1/lib/arbre/version.rb 0000644 0001750 0001750 00000000045 13523740213 016014 0 ustar samyak samyak module Arbre
VERSION = "1.2.1"
end
arbre-1.2.1/lib/arbre/rails/ 0000755 0001750 0001750 00000000000 13523740213 015115 5 ustar samyak samyak arbre-1.2.1/lib/arbre/rails/rendering.rb 0000644 0001750 0001750 00000000453 13523740213 017421 0 ustar samyak samyak module Arbre
module Rails
module Rendering
def render(*args)
rendered = helpers.render(*args)
case rendered
when Arbre::Context
current_arbre_element.add_child rendered
else
text_node rendered
end
end
end
end
end
arbre-1.2.1/lib/arbre/rails/forms.rb 0000644 0001750 0001750 00000004155 13523740213 016575 0 ustar samyak samyak module Arbre
module Rails
module Forms
class FormBuilderProxy < Arbre::Component
attr_reader :form_builder
# Since label and select are Arbre Elements already, we must
# override it here instead of letting method_missing
# deal with it
def label(*args)
proxy_call_to_form :label, *args
end
def select(*args)
proxy_call_to_form :select, *args
end
def respond_to_missing?(method, include_all)
if form_builder && form_builder.respond_to?(method, include_all)
true
else
super
end
end
private
def proxy_call_to_form(method, *args, &block)
text_node form_builder.send(method, *args, &block)
end
def method_missing(method, *args, &block)
if form_builder && form_builder.respond_to?(method)
proxy_call_to_form(method, *args, &block)
else
super
end
end
end
class FormForProxy < FormBuilderProxy
builder_method :form_for
def build(resource, form_options = {}, &block)
form_string = helpers.form_for(resource, form_options) do |f|
@form_builder = f
end
@opening_tag, @closing_tag = split_string_on(form_string, "")
super(&block)
end
def fields_for(*args, &block)
insert_tag FieldsForProxy, form_builder, *args, &block
end
def split_string_on(string, match)
return "" unless string && match
part_1 = string.split(Regexp.new("#{match}\\z")).first
[part_1, match]
end
def opening_tag
@opening_tag || ""
end
def closing_tag
@closing_tag || ""
end
end
class FieldsForProxy < FormBuilderProxy
def build(form_builder, *args, &block)
form_builder.fields_for(*args) do |f|
@form_builder = f
end
super(&block)
end
def to_s
children.to_s
end
end
end
end
end
arbre-1.2.1/lib/arbre/rails/template_handler.rb 0000644 0001750 0001750 00000000553 13523740213 020755 0 ustar samyak samyak module Arbre
module Rails
class TemplateHandler
def call(template, source = nil)
source = template.source unless source
<<-END
Arbre::Context.new(assigns, self) {
#{source}
}.to_s
END
end
end
end
end
ActionView::Template.register_template_handler :arb, Arbre::Rails::TemplateHandler.new
arbre-1.2.1/lib/arbre/element.rb 0000644 0001750 0001750 00000007565 13523740213 015776 0 ustar samyak samyak require 'arbre/element/builder_methods'
require 'arbre/element/proxy'
require 'arbre/element_collection'
module Arbre
class Element
include BuilderMethods
attr_reader :parent
attr_reader :children, :arbre_context
def initialize(arbre_context = Arbre::Context.new)
@arbre_context = arbre_context
@children = ElementCollection.new
@parent = nil
end
def assigns
arbre_context.assigns
end
def helpers
arbre_context.helpers
end
def tag_name
@tag_name ||= self.class.name.demodulize.downcase
end
def build(*args, &block)
# Render the block passing ourselves in
append_return_block(block.call(self)) if block
end
def add_child(child)
return unless child
if child.is_a?(Array)
child.each{|item| add_child(item) }
return @children
end
# If its not an element, wrap it in a TextNode
unless child.is_a?(Element)
child = Arbre::HTML::TextNode.from_string(child)
end
if child.respond_to?(:parent)
# Remove the child
child.parent.remove_child(child) if child.parent && child.parent != self
# Set ourselves as the parent
child.parent = self
end
@children << child
end
def remove_child(child)
child.parent = nil if child.respond_to?(:parent=)
@children.delete(child)
end
def <<(child)
add_child(child)
end
def children?
@children.any?
end
def parent=(parent)
@parent = parent
end
def parent?
!@parent.nil?
end
def ancestors
if parent?
[parent] + parent.ancestors
else
[]
end
end
# TODO: Shouldn't grab whole tree
def find_first_ancestor(type)
ancestors.find{|a| a.is_a?(type) }
end
def content=(contents)
clear_children!
add_child(contents)
end
def get_elements_by_tag_name(tag_name)
elements = ElementCollection.new
children.each do |child|
elements << child if child.tag_name == tag_name
elements.concat(child.get_elements_by_tag_name(tag_name))
end
elements
end
alias_method :find_by_tag, :get_elements_by_tag_name
def get_elements_by_class_name(class_name)
elements = ElementCollection.new
children.each do |child|
elements << child if child.class_list.include?(class_name)
elements.concat(child.get_elements_by_class_name(class_name))
end
elements
end
alias_method :find_by_class, :get_elements_by_class_name
def content
children.to_s
end
def html_safe
to_s
end
def indent_level
parent? ? parent.indent_level + 1 : 0
end
def each(&block)
[to_s].each(&block)
end
def inspect
to_s
end
def to_str
to_s
end
def to_s
content
end
def +(element)
case element
when Element, ElementCollection
else
element = Arbre::HTML::TextNode.from_string(element)
end
to_ary + element
end
def to_ary
ElementCollection.new [Proxy.new(self)]
end
alias_method :to_a, :to_ary
private
# Resets the Elements children
def clear_children!
@children.clear
end
# Implements the method lookup chain. When you call a method that
# doesn't exist, we:
#
# 1. Try to call the method on the current DOM context
# 2. Return an assigned variable of the same name
# 3. Call the method on the helper object
# 4. Call super
#
def method_missing(name, *args, &block)
if current_arbre_element.respond_to?(name)
current_arbre_element.send name, *args, &block
elsif assigns && assigns.has_key?(name)
assigns[name]
elsif helpers.respond_to?(name)
helpers.send(name, *args, &block)
else
super
end
end
end
end
arbre-1.2.1/lib/arbre/element_collection.rb 0000644 0001750 0001750 00000000560 13523740213 020175 0 ustar samyak samyak module Arbre
# Stores a collection of Element objects
class ElementCollection < Array
def +(other)
self.class.new(super)
end
def -(other)
self.class.new(super)
end
def &(other)
self.class.new(super)
end
def to_s
self.collect do |element|
element.to_s
end.join('').html_safe
end
end
end
arbre-1.2.1/Gemfile.lock 0000644 0001750 0001750 00000012445 13523740213 014372 0 ustar samyak samyak PATH
remote: .
specs:
arbre (1.2.1)
activesupport (>= 3.0.0)
GEM
remote: http://rubygems.org/
specs:
actioncable (5.2.3)
actionpack (= 5.2.3)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailer (5.2.3)
actionpack (= 5.2.3)
actionview (= 5.2.3)
activejob (= 5.2.3)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (5.2.3)
actionview (= 5.2.3)
activesupport (= 5.2.3)
rack (~> 2.0)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.2.3)
activesupport (= 5.2.3)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.2.3)
activesupport (= 5.2.3)
globalid (>= 0.3.6)
activemodel (5.2.3)
activesupport (= 5.2.3)
activerecord (5.2.3)
activemodel (= 5.2.3)
activesupport (= 5.2.3)
arel (>= 9.0)
activestorage (5.2.3)
actionpack (= 5.2.3)
activerecord (= 5.2.3)
marcel (~> 0.3.1)
activesupport (5.2.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
arel (9.0.0)
ast (2.4.0)
builder (3.2.3)
capybara (3.15.0)
addressable
mini_mime (>= 0.1.3)
nokogiri (~> 1.8)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
regexp_parser (~> 1.2)
xpath (~> 3.2)
chandler (0.9.0)
netrc
octokit (>= 2.2.0)
coderay (1.1.2)
combustion (1.1.0)
activesupport (>= 3.0.0)
railties (>= 3.0.0)
thor (>= 0.14.6)
concurrent-ruby (1.1.5)
crass (1.0.4)
diff-lcs (1.3)
erubi (1.8.0)
faraday (0.15.4)
multipart-post (>= 1.2, < 3)
ffi (1.9.25-java)
globalid (0.4.2)
activesupport (>= 4.2.0)
i18n (1.6.0)
concurrent-ruby (~> 1.0)
jar-dependencies (0.4.0)
jaro_winkler (1.5.2)
jaro_winkler (1.5.2-java)
loofah (2.2.3)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
mini_mime (>= 0.1.1)
marcel (0.3.3)
mimemagic (~> 0.3.2)
method_source (0.9.2)
mimemagic (0.3.3)
mini_mime (1.0.1)
mini_portile2 (2.4.0)
minitest (5.11.3)
multipart-post (2.0.0)
netrc (0.11.0)
nio4r (2.3.1)
nio4r (2.3.1-java)
nokogiri (1.10.2)
mini_portile2 (~> 2.4.0)
nokogiri (1.10.2-java)
octokit (4.13.0)
sawyer (~> 0.8.0, >= 0.5.3)
parallel (1.17.0)
parser (2.6.2.1)
ast (~> 2.4.0)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
pry (0.12.2-java)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
spoon (~> 0.0)
psych (3.1.0)
psych (3.1.0-java)
jar-dependencies (>= 0.1.7)
public_suffix (3.0.3)
rack (2.0.6)
rack-test (1.1.0)
rack (>= 1.0, < 3)
rails (5.2.3)
actioncable (= 5.2.3)
actionmailer (= 5.2.3)
actionpack (= 5.2.3)
actionview (= 5.2.3)
activejob (= 5.2.3)
activemodel (= 5.2.3)
activerecord (= 5.2.3)
activestorage (= 5.2.3)
activesupport (= 5.2.3)
bundler (>= 1.3.0)
railties (= 5.2.3)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.0.4)
loofah (~> 2.2, >= 2.2.2)
railties (5.2.3)
actionpack (= 5.2.3)
activesupport (= 5.2.3)
method_source
rake (>= 0.8.7)
thor (>= 0.19.0, < 2.0)
rainbow (3.0.0)
rake (12.3.2)
regexp_parser (1.3.0)
rspec (3.8.0)
rspec-core (~> 3.8.0)
rspec-expectations (~> 3.8.0)
rspec-mocks (~> 3.8.0)
rspec-core (3.8.0)
rspec-support (~> 3.8.0)
rspec-expectations (3.8.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-mocks (3.8.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-rails (3.8.2)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 3.8.0)
rspec-expectations (~> 3.8.0)
rspec-mocks (~> 3.8.0)
rspec-support (~> 3.8.0)
rspec-support (3.8.0)
rubocop (0.67.2)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
parser (>= 2.5, != 2.5.1.1)
psych (>= 3.1.0)
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 1.6)
ruby-progressbar (1.10.0)
sawyer (0.8.1)
addressable (>= 2.3.5, < 2.6)
faraday (~> 0.8, < 1.0)
spoon (0.0.6)
ffi
sprockets (3.7.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
thor (0.20.3)
thread_safe (0.3.6)
thread_safe (0.3.6-java)
tzinfo (1.2.5)
thread_safe (~> 0.1)
unicode-display_width (1.5.0)
websocket-driver (0.7.0)
websocket-extensions (>= 0.1.0)
websocket-driver (0.7.0-java)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.3)
xpath (3.2.0)
nokogiri (~> 1.8)
PLATFORMS
java
ruby
DEPENDENCIES
arbre!
capybara
chandler
combustion
pry
rails (>= 5.0.0.1)
rake
rspec
rspec-rails
rubocop
BUNDLED WITH
2.0.1
arbre-1.2.1/Gemfile 0000644 0001750 0001750 00000000454 13523740213 013440 0 ustar samyak samyak source 'http://rubygems.org'
gemspec
gem 'rake'
group :test do
gem 'rspec'
gem 'pry'
end
group :tools do
gem 'rubocop'
end
group :release do
gem 'chandler'
end
group :rails do
gem 'rails', '>= 5.0.0.1' # fixes CVE-2016-6316
gem 'rspec-rails'
gem 'combustion'
gem 'capybara'
end
arbre-1.2.1/.gitignore 0000644 0001750 0001750 00000000133 13523740213 014127 0 ustar samyak samyak *.gem
.bundle
pkg/*
benchmarks
.rvmrc
.ruby-version
.ruby-gemset
tags
.DS_Store
docs/_site
arbre-1.2.1/arbre.gemspec 0000644 0001750 0001750 00000001416 13523740213 014604 0 ustar samyak samyak # -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "arbre/version"
Gem::Specification.new do |s|
s.name = "arbre"
s.version = Arbre::VERSION
s.platform = Gem::Platform::RUBY
s.authors = ["Greg Bell"]
s.email = ["gregdbell@gmail.com"]
s.homepage = ""
s.summary = %q{An Object Oriented DOM Tree in Ruby}
s.description = %q{An Object Oriented DOM Tree in Ruby}
s.license = "MIT"
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]
s.required_ruby_version = '>= 2.3'
s.add_dependency("activesupport", ">= 3.0.0")
end
arbre-1.2.1/docs/ 0000755 0001750 0001750 00000000000 13523740213 013072 5 ustar samyak samyak arbre-1.2.1/docs/_includes/ 0000755 0001750 0001750 00000000000 13523740213 015037 5 ustar samyak samyak arbre-1.2.1/docs/_includes/top-menu.html 0000644 0001750 0001750 00000000434 13523740213 017472 0 ustar samyak samyak
arbre-1.2.1/docs/index.md 0000644 0001750 0001750 00000007066 13523740213 014534 0 ustar samyak samyak ---
redirect_from: /docs/documentation.html
---
# Arbre
HTML Views in Ruby
### Introduction
Arbre is a alternate template system for [Ruby on Rails Action View](http://guides.rubyonrails.org/action_view_overview.html).
Arbre expresses HTML using a Ruby DSL, which makes it similar to the [Builder](https://github.com/tenderlove/builder) gem for XML.
Arbre was extracted from [Active Admin](https://activeadmin.info/).
An example `index.html.arb`:
```ruby
html {
head {
title "Welcome page"
}
body {
para "Hello, world"
}
}
```
The purpose of Arbre is to leave the view as Ruby objects as long as possible,
which allows an object-oriented approach including inheritance, composition, and encapsulation.
### Installation
Add gem `arbre` to your `Gemfile` and `bundle install`.
Arbre registers itself as a Rails template handler for files with an extension `.arb`.
### Tags
Arbre DSL is composed of HTML tags. Tag attributes including `id` and HTML classes are passed as a hash parameter and the tag body is passed as a block. Most HTML5 tags are implemented, including `script`, `embed` and `video`.
A special case is the paragraph tag,
, which is mapped to `para`.
JavaScript can be included by using `script { raw ... }`
To include text that is not immediately part of a tag use `text_node`.
### Components
Arbre DSL can be extended by defining new tags composed of other, simpler tags.
This provides a simpler alternative to nesting partials.
The recommended approach is to subclass Arbre::Component and implement a new builder method.
The builder_method defines the method that will be called to build this component
when using the DSL. The arguments passed into the builder_method will be passed
into the #build method for you.
For example:
```ruby
class Panel < Arbre::Component
builder_method :panel
def build(title, attributes = {})
super(attributes)
h3(title, class: "panel-title")
end
end
```
By default components are `div` tags with an HTML class corresponding to the component class name. This can be overridden by redefining the `tag_name` method.
Several examples of Arbre components are [included in Active Admin](https://activeadmin.info/12-arbre-components.html)
### Contexts
An [Arbre::Context](http://www.rubydoc.info/gems/arbre/Arbre/Context) is an object in which Arbre DSL is interpreted, providing a root for the Ruby DOM that can be [searched and manipulated](http://www.rubydoc.info/gems/arbre/Arbre/Element). A context is automatically provided when a `.arb` template or partial is loaded. Contexts can be used when developing or testing a component. Contexts are rendered by calling to_s.
```ruby
html = Arbre::Context.new do
panel "Hello World", id: "my-panel" do
span "Inside the panel"
text_node "Plain text"
end
end
puts html.to_s # =>
```
```html
{% include google-analytics.html %}
arbre-1.2.1/docs/_config.yml 0000644 0001750 0001750 00000000125 13523740213 015217 0 ustar samyak samyak plugins:
- jekyll-redirect-from
defaults:
-
values:
layout: "default"
arbre-1.2.1/spec/ 0000755 0001750 0001750 00000000000 13523740213 013074 5 ustar samyak samyak arbre-1.2.1/spec/support/ 0000755 0001750 0001750 00000000000 13523740213 014610 5 ustar samyak samyak arbre-1.2.1/spec/support/bundle.rb 0000644 0001750 0001750 00000000132 13523740213 016402 0 ustar samyak samyak $LOAD_PATH.unshift(File.expand_path("../../", __FILE__))
require "bundler"
Bundler.setup
arbre-1.2.1/spec/changelog_spec.rb 0000644 0001750 0001750 00000001203 13523740213 016356 0 ustar samyak samyak require 'spec_helper'
describe "Changelog" do
subject(:changelog) do
path = File.join(File.dirname(__dir__), "CHANGELOG.md")
File.read(path)
end
it 'has definitions for all implicit links' do
implicit_link_names = changelog.scan(/\[([^\]]+)\]\[\]/).flatten.uniq
implicit_link_names.each do |name|
expect(changelog).to include("[#{name}]: https")
end
end
describe 'entry' do
let(:lines) { changelog.each_line }
subject(:entries) { lines.grep(/^\*/) }
it 'does not end with a punctuation' do
entries.each do |entry|
expect(entry).not_to match(/\.$/)
end
end
end
end
arbre-1.2.1/spec/rails/ 0000755 0001750 0001750 00000000000 13523740213 014206 5 ustar samyak samyak arbre-1.2.1/spec/rails/support/ 0000755 0001750 0001750 00000000000 13523740213 015722 5 ustar samyak samyak arbre-1.2.1/spec/rails/support/mock_person.rb 0000644 0001750 0001750 00000000236 13523740213 020567 0 ustar samyak samyak require 'active_model'
class MockPerson
extend ActiveModel::Naming
attr_accessor :name
def persisted?
false
end
def to_key
[]
end
end
arbre-1.2.1/spec/rails/templates/ 0000755 0001750 0001750 00000000000 13523740213 016204 5 ustar samyak samyak arbre-1.2.1/spec/rails/templates/arbre/ 0000755 0001750 0001750 00000000000 13523740213 017277 5 ustar samyak samyak arbre-1.2.1/spec/rails/templates/arbre/_partial_with_assignment.arb 0000644 0001750 0001750 00000000043 13523740213 025040 0 ustar samyak samyak para "Partial: #{my_instance_var}"
arbre-1.2.1/spec/rails/templates/arbre/page_with_arb_partial_and_assignment.arb 0000644 0001750 0001750 00000000116 13523740213 027344 0 ustar samyak samyak h1 "Before Partial"
render "arbre/partial_with_assignment"
h2 "After Partial"
arbre-1.2.1/spec/rails/templates/arbre/page_with_assignment.arb 0000644 0001750 0001750 00000000023 13523740213 024157 0 ustar samyak samyak h1 my_instance_var
arbre-1.2.1/spec/rails/templates/arbre/empty.arb 0000644 0001750 0001750 00000000000 13523740213 021111 0 ustar samyak samyak arbre-1.2.1/spec/rails/templates/arbre/page_with_erb_partial.arb 0000644 0001750 0001750 00000000074 13523740213 024301 0 ustar samyak samyak h1 "Before Partial"
render "erb/partial"
h2 "After Partial"
arbre-1.2.1/spec/rails/templates/arbre/_partial.arb 0000644 0001750 0001750 00000000034 13523740213 021555 0 ustar samyak samyak para "Hello from a partial"
arbre-1.2.1/spec/rails/templates/arbre/page_with_partial.arb 0000644 0001750 0001750 00000000076 13523740213 023453 0 ustar samyak samyak h1 "Before Partial"
render "arbre/partial"
h2 "After Partial"
arbre-1.2.1/spec/rails/templates/arbre/simple_page.arb 0000644 0001750 0001750 00000000131 13523740213 022245 0 ustar samyak samyak html do
head do
end
body do
h1 "Hello World"
para "Hello again!"
end
end
arbre-1.2.1/spec/rails/templates/erb/ 0000755 0001750 0001750 00000000000 13523740213 016754 5 ustar samyak samyak arbre-1.2.1/spec/rails/templates/erb/_partial.erb 0000644 0001750 0001750 00000000041 13523740213 021234 0 ustar samyak samyak
Hello from an erb partial
arbre-1.2.1/spec/rails/stub_app/ 0000755 0001750 0001750 00000000000 13523740213 016023 5 ustar samyak samyak arbre-1.2.1/spec/rails/stub_app/config/ 0000755 0001750 0001750 00000000000 13523740213 017270 5 ustar samyak samyak arbre-1.2.1/spec/rails/stub_app/config/database.yml 0000644 0001750 0001750 00000000100 13523740213 021546 0 ustar samyak samyak test:
adapter: sqlite3
database: db/combustion_test.sqlite
arbre-1.2.1/spec/rails/stub_app/config/routes.rb 0000644 0001750 0001750 00000000051 13523740213 021132 0 ustar samyak samyak Rails.application.routes.draw do
#
end
arbre-1.2.1/spec/rails/stub_app/log/ 0000755 0001750 0001750 00000000000 13523740213 016604 5 ustar samyak samyak arbre-1.2.1/spec/rails/stub_app/log/.gitignore 0000644 0001750 0001750 00000000006 13523740213 020570 0 ustar samyak samyak *.log
arbre-1.2.1/spec/rails/stub_app/public/ 0000755 0001750 0001750 00000000000 13523740213 017301 5 ustar samyak samyak arbre-1.2.1/spec/rails/stub_app/public/favicon.ico 0000644 0001750 0001750 00000000000 13523740213 021410 0 ustar samyak samyak arbre-1.2.1/spec/rails/stub_app/db/ 0000755 0001750 0001750 00000000000 13523740213 016410 5 ustar samyak samyak arbre-1.2.1/spec/rails/stub_app/db/schema.rb 0000644 0001750 0001750 00000000055 13523740213 020175 0 ustar samyak samyak # ActiveRecord::Schema.define do
# #
# end
arbre-1.2.1/spec/rails/integration/ 0000755 0001750 0001750 00000000000 13523740213 016531 5 ustar samyak samyak arbre-1.2.1/spec/rails/integration/forms_spec.rb 0000644 0001750 0001750 00000004651 13523740213 021224 0 ustar samyak samyak require 'rails/rails_spec_helper'
describe "Building forms" do
let(:assigns){ {} }
let(:helpers){ mock_action_view }
let(:html) { form.to_s }
describe "building a simple form for" do
let(:form) do
arbre do
form_for MockPerson.new, url: "/" do |f|
f.label :name
f.text_field :name
end
end
end
it "should build a form" do
expect(html).to have_selector("form")
end
it "should include the hidden authenticity token" do
expect(html).to include ''
end
it "should create a label" do
expect(html).to have_selector("form label[for=mock_person_name]")
end
it "should create a text field" do
expect(html).to have_selector("form input[type=text]")
end
end
describe "building a form with fields for" do
let(:form) do
arbre do
form_for MockPerson.new, url: "/" do |f|
f.label :name
f.text_field :name
f.fields_for :permission do |pf|
pf.label :admin
pf.check_box :admin
end
end
end
end
it "should render nested label" do
expect(html).to have_selector("form label[for=mock_person_permission_admin]", text: "Admin")
end
it "should render nested label" do
expect(html).to have_selector("form input[type=checkbox][name='mock_person[permission][admin]']")
end
it "should not render a div for the proxy" do
expect(html).not_to have_selector("form div.fields_for_proxy")
end
end
describe "forms with other elements" do
let(:form) do
arbre do
form_for MockPerson.new, url: "/" do |f|
div do
f.label :name
f.text_field :name
end
para do
f.label :name
f.text_field :name
end
div class: "permissions" do
f.fields_for :permission do |pf|
div class: "permissions_label" do
pf.label :admin
end
pf.check_box :admin
end
end
end
end
end
it "should correctly nest elements" do
expect(html).to have_selector("form > p > label")
end
it "should correnctly nest elements within fields for" do
expect(html).to have_selector("form > div.permissions > div.permissions_label label")
end
end
end
arbre-1.2.1/spec/rails/integration/rendering_spec.rb 0000644 0001750 0001750 00000005153 13523740213 022051 0 ustar samyak samyak require 'rails/rails_spec_helper'
ARBRE_VIEWS_PATH = File.expand_path("../../templates", __FILE__)
class TestController < ActionController::Base
append_view_path ARBRE_VIEWS_PATH
def render_empty
render "arbre/empty"
end
def render_simple_page
render "arbre/simple_page"
end
def render_partial
render "arbre/page_with_partial"
end
def render_erb_partial
render "arbre/page_with_erb_partial"
end
def render_with_instance_variable
@my_instance_var = "From Instance Var"
render "arbre/page_with_assignment"
end
def render_partial_with_instance_variable
@my_instance_var = "From Instance Var"
render "arbre/page_with_arb_partial_and_assignment"
end
end
describe TestController, "Rendering with Arbre", type: :request do
let(:body){ response.body }
before do
Rails.application.routes.draw do
get 'test/render_empty', controller: "test"
get 'test/render_simple_page', controller: "test"
get 'test/render_partial', controller: "test"
get 'test/render_erb_partial', controller: "test"
get 'test/render_with_instance_variable', controller: "test"
get 'test/render_partial_with_instance_variable', controller: "test"
get 'test/render_page_with_helpers', controller: "test"
end
end
after do
Rails.application.reload_routes!
end
it "should render the empty template" do
get "/test/render_empty"
expect(response).to be_successful
end
it "should render a simple page" do
get "/test/render_simple_page"
expect(response).to be_successful
expect(body).to have_selector("h1", text: "Hello World")
expect(body).to have_selector("p", text: "Hello again!")
end
it "should render an arb partial" do
get "/test/render_partial"
expect(response).to be_successful
expect(body).to eq <<~HTML
Before Partial
Hello from a partial
After Partial
HTML
end
it "should render an erb (or other) partial" do
get "/test/render_erb_partial"
expect(response).to be_successful
expect(body).to eq <<~HTML
Before Partial
Hello from an erb partial
After Partial
HTML
end
it "should render with instance variables" do
get "/test/render_with_instance_variable"
expect(response).to be_successful
expect(body).to have_selector("h1", text: "From Instance Var")
end
it "should render an arbre partial with assignments" do
get "/test/render_partial_with_instance_variable"
expect(response).to be_successful
expect(body).to have_selector("p", text: "Partial: From Instance Var")
end
end
arbre-1.2.1/spec/rails/rails_spec_helper.rb 0000644 0001750 0001750 00000001572 13523740213 020223 0 ustar samyak samyak require 'rubygems'
require 'bundler/setup'
require 'combustion'
Combustion.path = 'spec/rails/stub_app'
Combustion.initialize! :action_controller,
:action_view
require 'rspec/rails'
require 'capybara/rspec'
require 'capybara/rails'
require 'spec_helper'
require 'rails/support/mock_person'
# Ensure that the rails plugin is installed
require 'arbre/rails'
module AdditionalHelpers
def protect_against_forgery?
true
end
def form_authenticity_token(form_options: {})
"AUTH_TOKEN"
end
end
def mock_action_view(assigns = {})
controller = ActionView::TestCase::TestController.new
ActionView::Base.send :include, ActionView::Helpers
ActionView::Base.send :include, AdditionalHelpers
ActionView::Base.new(ActionController::Base.view_paths, assigns, controller)
end
RSpec.configure do |config|
config.include Capybara::RSpecMatchers
end
arbre-1.2.1/spec/arbre/ 0000755 0001750 0001750 00000000000 13523740213 014167 5 ustar samyak samyak arbre-1.2.1/spec/arbre/integration/ 0000755 0001750 0001750 00000000000 13523740213 016512 5 ustar samyak samyak arbre-1.2.1/spec/arbre/integration/html_spec.rb 0000644 0001750 0001750 00000011111 13523740213 021010 0 ustar samyak samyak require 'spec_helper'
describe Arbre do
let(:helpers){ nil }
let(:assigns){ {} }
it "should render a single element" do
expect(arbre {
span "Hello World"
}.to_s).to eq("Hello World\n")
end
it "should render a child element" do
expect(arbre {
span do
span "Hello World"
end
}.to_s).to eq <<~HTML
Hello World
HTML
end
it "should render an unordered list" do
expect(arbre {
ul do
li "First"
li "Second"
li "Third"
end
}.to_s).to eq <<~HTML
First
Second
Third
HTML
end
it "should allow local variables inside the tags" do
expect(arbre {
first = "First"
second = "Second"
ul do
li first
li second
end
}.to_s).to eq <<~HTML
First
Second
HTML
end
it "should add children and nested" do
expect(arbre {
div do
ul
li do
li
end
end
}.to_s).to eq <<~HTML
HTML
end
it "should pass the element in to the block if asked for" do
expect(arbre {
div do |d|
d.ul do
li
end
end
}.to_s).to eq <<~HTML
HTML
end
it "should move content tags between parents" do
expect(arbre {
div do
span(ul(li))
end
}.to_s).to eq <<~HTML
HTML
end
it "should add content to the parent if the element is passed into block" do
expect(arbre {
div do |d|
d.id = "my-tag"
ul do
li
end
end
}.to_s).to eq <<~HTML
HTML
end
it "should have the parent set on it" do
list, item = nil
arbre {
list = ul do
li "Hello"
item = li "World"
end
}
expect(item.parent).to eq list
end
it "should set a string content return value with no children" do
expect(arbre {
li do
"Hello World"
end
}.to_s).to eq <<~HTML
Hello World
HTML
end
it "should turn string return values into text nodes" do
node = nil
arbre {
list = li do
"Hello World"
end
node = list.children.first
}
expect(node).to be_a Arbre::HTML::TextNode
end
it "should not render blank arrays" do
expect(arbre {
tbody do
[]
end
}.to_s).to eq <<~HTML
HTML
end
describe "self-closing nodes" do
it "should not self-close script tags" do
expect(arbre {
script type: 'text/javascript'
}.to_s).to eq("\n")
end
it "should self-close meta tags" do
expect(arbre {
meta content: "text/html; charset=utf-8"
}.to_s).to eq("\n")
end
it "should self-close link tags" do
expect(arbre {
link rel: "stylesheet"
}.to_s).to eq("\n")
end
Arbre::HTML::Tag::SELF_CLOSING_ELEMENTS.each do |tag|
it "should self-close #{tag} tags" do
expect(arbre {
send(tag)
}.to_s).to eq("<#{tag}/>\n")
end
end
end
describe "html safe" do
it "should escape the contents" do
expect(arbre {
span(" ")
}.to_s).to eq <<~HTML
<br />
HTML
end
it "should return html safe strings" do
expect(arbre {
span(" ")
}.to_s).to be_html_safe
end
it "should not escape html passed in" do
expect(arbre {
span(span(" "))
}.to_s).to eq <<~HTML
<br />
HTML
end
it "should escape string contents when passed in block" do
expect(arbre {
span {
span {
" "
}
}
}.to_s).to eq <<~HTML
<br />
HTML
end
it "should escape the contents of attributes" do
expect(arbre {
span(class: " ")
}.to_s).to eq <<~HTML
HTML
end
end
end
arbre-1.2.1/spec/arbre/unit/ 0000755 0001750 0001750 00000000000 13523740213 015146 5 ustar samyak samyak arbre-1.2.1/spec/arbre/unit/component_spec.rb 0000644 0001750 0001750 00000001611 13523740213 020506 0 ustar samyak samyak require 'spec_helper'
# A mock subclass to play with
class MockComponent < Arbre::Component
builder_method :mock_component
def build
h2 "Hello World"
end
end
describe Arbre::Component do
let(:assigns) { {} }
let(:helpers) { nil }
let(:component_class){ MockComponent }
let(:component){ component_class.new }
it "should be a subclass of an html div" do
expect(Arbre::Component.ancestors).to include(Arbre::HTML::Div)
end
it "should render to a div, even as a subclass" do
expect(component.tag_name).to eq('div')
end
it "should add a class by default" do
expect(component.class_list).to include("mock_component")
end
it "should render the object using the builder method name" do
comp = expect(arbre {
mock_component
}.to_s).to eq <<~HTML
Hello World
HTML
end
end
arbre-1.2.1/spec/arbre/unit/html/ 0000755 0001750 0001750 00000000000 13523740213 016112 5 ustar samyak samyak arbre-1.2.1/spec/arbre/unit/html/tag_attributes_spec.rb 0000644 0001750 0001750 00000003233 13523740213 022473 0 ustar samyak samyak require 'spec_helper'
describe Arbre::HTML::Tag, "Attributes" do
let(:tag){ Arbre::HTML::Tag.new }
describe "attributes" do
before { tag.build id: "my_id" }
it "should have an attributes hash" do
expect(tag.attributes).to eq({id: "my_id"})
end
it "should render the attributes to html" do
expect(tag.to_s).to eq "\n"
end
it "shouldn't render attributes that are empty" do
tag.class_list # initializes an empty ClassList
tag.set_attribute :foo, ''
tag.set_attribute :bar, nil
expect(tag.to_s).to eq "\n"
end
it "should get an attribute value" do
expect(tag.attr(:id)).to eq("my_id")
end
describe "#has_attribute?" do
context "when the attribute exists" do
it "should return true" do
expect(tag.has_attribute?(:id)).to eq(true)
end
end
context "when the attribute does not exist" do
it "should return false" do
expect(tag.has_attribute?(:class)).to eq(false)
end
end
end
it "should remove an attribute" do
expect(tag.attributes).to eq({id: "my_id"})
expect(tag.remove_attribute(:id)).to eq("my_id")
expect(tag.attributes).to eq({})
end
end
describe "rendering attributes" do
it "should html safe the attribute values" do
tag.set_attribute(:class, '">bad things!')
expect(tag.to_s).to eq "\n"
end
it "should should escape the attribute names" do
tag.set_attribute(">bad", "things")
expect(tag.to_s).to eq "\n"
end
end
end
arbre-1.2.1/spec/arbre/unit/html/class_list_spec.rb 0000644 0001750 0001750 00000000514 13523740213 021611 0 ustar samyak samyak require 'spec_helper'
describe Arbre::HTML::ClassList do
describe ".build_from_string" do
it "should build a new list from a string of classes" do
list = Arbre::HTML::ClassList.build_from_string("first second")
expect(list.size).to eq(2)
expect(list).to match_array(%w{first second})
end
end
end
arbre-1.2.1/spec/arbre/unit/html/tag_spec.rb 0000644 0001750 0001750 00000005530 13523740213 020227 0 ustar samyak samyak require 'spec_helper'
describe Arbre::HTML::Tag do
let(:tag){ Arbre::HTML::Tag.new }
describe "building a new tag" do
before { tag.build "Hello World", id: "my_id" }
it "should set the contents to a string" do
expect(tag.content).to eq("Hello World")
end
it "should set the hash of options to the attributes" do
expect(tag.attributes).to eq({ id: "my_id" })
end
end
describe "creating a tag 'for' an object" do
let(:model_name){ double(singular: "resource_class")}
let(:resource_class){ double(model_name: model_name) }
let(:resource){ double(class: resource_class, to_key: ['5'])}
before do
tag.build for: resource
end
it "should set the id to the type and id" do
expect(tag.id).to eq("resource_class_5")
end
it "should add a class name" do
expect(tag.class_list).to include("resource_class")
end
describe "for an object that doesn't have a model_name" do
let(:resource_class){ double(name: 'ResourceClass') }
before do
tag.build for: resource
end
it "should set the id to the type and id" do
expect(tag.id).to eq("resource_class_5")
end
it "should add a class name" do
expect(tag.class_list).to include("resource_class")
end
end
describe "with a default_id_for_prefix" do
let(:tag) do
Class.new(Arbre::HTML::Tag) do
def default_id_for_prefix
"a_prefix"
end
end.new
end
it "should set the id to the type and id" do
expect(tag.id).to eq("a_prefix_resource_class_5")
end
end
end
describe "creating a tag with a for attribute" do
it "sets the `for` attribute when a string is given" do
tag.build for: "email"
expect(tag.attributes[:for]).to eq "email"
end
it "sets the `for` attribute when a symbol is given" do
tag.build for: :email
expect(tag.attributes[:for]).to eq :email
end
end
describe "css class names" do
it "should add a class" do
tag.add_class "hello_world"
expect(tag.class_names).to eq("hello_world")
end
it "should remove_class" do
tag.add_class "hello_world"
expect(tag.class_names).to eq("hello_world")
tag.remove_class "hello_world"
expect(tag.class_names).to eq("")
end
it "should not add a class if it already exists" do
tag.add_class "hello_world"
tag.add_class "hello_world"
expect(tag.class_names).to eq("hello_world")
end
it "should seperate classes with space" do
tag.add_class "hello world"
expect(tag.class_list.size).to eq(2)
end
it "should create a class list from a string" do
tag = Arbre::HTML::Tag.new
tag.build(class: "first-class")
tag.add_class "second-class"
expect(tag.class_list.size).to eq(2)
end
end
end
arbre-1.2.1/spec/arbre/unit/html/text_node_spec.rb 0000644 0001750 0001750 00000000076 13523740213 021445 0 ustar samyak samyak require 'spec_helper'
describe Arbre::HTML::TextNode do
end
arbre-1.2.1/spec/arbre/unit/context_spec.rb 0000644 0001750 0001750 00000001504 13523740213 020171 0 ustar samyak samyak # coding: utf-8
require 'spec_helper'
describe Arbre::Context do
let(:context) do
Arbre::Context.new do
h1 "札幌市北区" # Add some HTML to the context
end
end
it "should not increment the indent_level" do
expect(context.indent_level).to eq(-1)
end
it "should return a bytesize" do
expect(context.bytesize).to eq(25)
end
it "should return a length" do
expect(context.length).to eq(25)
end
it "should delegate missing methods to the html string" do
expect(context).to respond_to(:index)
expect(context.index('<')).to eq(0)
end
it "should use a cached version of the HTML for method delegation" do
expect(context).to receive(:to_s).once.and_return("
札幌市北区
")
expect(context.index('<')).to eq(0)
expect(context.index('<')).to eq(0)
end
end
arbre-1.2.1/spec/arbre/unit/element_spec.rb 0000644 0001750 0001750 00000015751 13523740213 020147 0 ustar samyak samyak require 'spec_helper'
describe Arbre::Element do
let(:element){ Arbre::Element.new }
context "when initialized" do
it "should have no children" do
expect(element.children).to be_empty
end
it "should have no parent" do
expect(element.parent).to be_nil
end
it "should respond to the HTML builder methods" do
expect(element).to respond_to(:span)
end
it "should have a set of local assigns" do
context = Arbre::Context.new hello: "World"
element = Arbre::Element.new(context)
expect(element.assigns[:hello]).to eq("World")
end
it "should have an empty hash with no local assigns" do
expect(element.assigns).to eq({})
end
end
describe "passing in a helper object" do
let(:helper) do
Class.new do
def helper_method
"helper method"
end
end
end
let(:element){ Arbre::Element.new(Arbre::Context.new(nil, helper.new)) }
it "should call methods on the helper object and return TextNode objects" do
expect(element.helper_method).to eq("helper method")
end
it "should raise a NoMethodError if not found" do
expect {
element.a_method_that_doesnt_exist
}.to raise_error(NoMethodError)
end
end
describe "passing in assigns" do
let(:post){ double }
let(:assigns){ {post: post} }
it "should be accessible via a method call" do
element = Arbre::Element.new(Arbre::Context.new(assigns))
expect(element.post).to eq(post)
end
end
it "to_a.flatten should not infinitely recurse" do
Timeout.timeout(1) do
element.to_a.flatten
end
end
describe "adding a child" do
let(:child){ Arbre::Element.new }
before do
element.add_child child
end
it "should add the child to the parent" do
expect(element.children.first).to eq(child)
end
it "should set the parent of the child" do
expect(child.parent).to eq(element)
end
context "when the child is nil" do
let(:child){ nil }
it "should not add the child" do
expect(element.children).to be_empty
end
end
context "when the child is a string" do
let(:child){ "Hello World" }
it "should add as a TextNode" do
expect(element.children.first).to be_instance_of(Arbre::HTML::TextNode)
expect(element.children.first.to_s).to eq("Hello World")
end
end
end
describe "setting the content" do
context "when a string" do
before do
element.add_child "Hello World"
element.content = "Goodbye"
end
it "should clear the existing children" do
expect(element.children.size).to eq(1)
end
it "should add the string as a child" do
expect(element.children.first.to_s).to eq("Goodbye")
end
it "should html escape the string" do
string = "Goodbye "
element.content = string
expect(element.content.to_s).to eq("Goodbye <br />")
end
end
context "when an element" do
let(:content_element){ Arbre::Element.new }
before do
element.content = content_element
end
it "should set the content tag" do
expect(element.children.first).to eq(content_element)
end
it "should set the tags parent" do
expect(content_element.parent).to eq(element)
end
end
context "when an array of tags" do
let(:first){ Arbre::Element.new }
let(:second){ Arbre::Element.new }
before do
element.content = [first, second]
end
it "should set the content tag" do
expect(element.children.first).to eq(first)
end
it "should set the tags parent" do
expect(element.children.first.parent).to eq(element)
end
end
end
describe "rendering to html" do
before { @separator = $, }
after { $, = @separator }
let(:collection){ element + "hello world" }
it "should render the children collection" do
expect(element.children).to receive(:to_s).and_return("content")
expect(element.to_s).to eq("content")
end
it "should render collection when is set the default separator" do
$, = "_"
expect(collection.to_s).to eq("hello world")
end
it "should render collection when is not set the default separator" do
expect(collection.to_s).to eq("hello world")
end
end
describe "adding elements together" do
context "when both elements are tags" do
let(:first){ Arbre::Element.new }
let(:second){ Arbre::Element.new }
let(:collection){ first + second }
it "should return an instance of Collection" do
expect(collection).to be_an_instance_of(Arbre::ElementCollection)
end
it "should return the elements in the collection" do
expect(collection.size).to eq(2)
expect(collection.first).to eq(first)
expect(collection[1]).to eq(second)
end
end
context "when the left is a collection and the right is a tag" do
let(:first){ Arbre::Element.new }
let(:second){ Arbre::Element.new }
let(:third){ Arbre::Element.new }
let(:collection){ Arbre::ElementCollection.new([first, second]) + third}
it "should return an instance of Collection" do
expect(collection).to be_an_instance_of(Arbre::ElementCollection)
end
it "should return the elements in the collection flattened" do
expect(collection.size).to eq(3)
expect(collection[0]).to eq(first)
expect(collection[1]).to eq(second)
expect(collection[2]).to eq(third)
end
end
context "when the right is a collection and the left is a tag" do
let(:first){ Arbre::Element.new }
let(:second){ Arbre::Element.new }
let(:third){ Arbre::Element.new }
let(:collection){ first + Arbre::ElementCollection.new([second,third]) }
it "should return an instance of Collection" do
expect(collection).to be_an_instance_of(Arbre::ElementCollection)
end
it "should return the elements in the collection flattened" do
expect(collection.size).to eq(3)
expect(collection[0]).to eq(first)
expect(collection[1]).to eq(second)
expect(collection[2]).to eq(third)
end
end
context "when the left is a tag and the right is a string" do
let(:element){ Arbre::Element.new }
let(:collection){ element + "Hello World"}
it "should return an instance of Collection" do
expect(collection).to be_an_instance_of(Arbre::ElementCollection)
end
it "should return the elements in the collection" do
expect(collection.size).to eq(2)
expect(collection[0]).to eq(element)
expect(collection[1]).to be_an_instance_of(Arbre::HTML::TextNode)
end
end
context "when the left is a string and the right is a tag" do
let(:collection){ "hello World" + Arbre::Element.new}
it "should return a string" do
expect(collection.strip.chomp).to eq("hello World")
end
end
end
end
arbre-1.2.1/spec/arbre/unit/element_finder_methods_spec.rb 0000644 0001750 0001750 00000006145 13523740213 023216 0 ustar samyak samyak require 'spec_helper'
describe Arbre::Element, "Finder Methods" do
let(:assigns){ {} }
let(:helpers){ {} }
describe "finding elements by tag name" do
it "should return 0 when no elements exist" do
expect(arbre {
div
}.get_elements_by_tag_name("li").size).to eq(0)
end
it "should return a child element" do
html = arbre do
ul
li
ul
end
elements = html.get_elements_by_tag_name("li")
expect(elements.size).to eq(1)
expect(elements[0]).to be_instance_of(Arbre::HTML::Li)
end
it "should return multple child elements" do
html = arbre do
ul
li
ul
li
end
elements = html.get_elements_by_tag_name("li")
expect(elements.size).to eq(2)
expect(elements[0]).to be_instance_of(Arbre::HTML::Li)
expect(elements[1]).to be_instance_of(Arbre::HTML::Li)
end
it "should return children's child elements" do
html = arbre do
ul
li do
li
end
end
elements = html.get_elements_by_tag_name("li")
expect(elements.size).to eq(2)
expect(elements[0]).to be_instance_of(Arbre::HTML::Li)
expect(elements[1]).to be_instance_of(Arbre::HTML::Li)
expect(elements[1].parent).to eq(elements[0])
end
end
#TODO: describe "finding an element by id"
describe "finding an element by a class name" do
it "should return 0 when no elements exist" do
expect(arbre {
div
}.get_elements_by_class_name("my_class").size).to eq(0)
end
it "should allow text nodes on tree" do
expect(arbre {
text_node "text"
}.get_elements_by_class_name("my_class").size).to eq(0)
end
it "should return a child element" do
html = arbre do
div class: "some_class"
div class: "my_class"
end
elements = html.get_elements_by_class_name("my_class")
expect(elements.size).to eq(1)
expect(elements[0]).to be_instance_of(Arbre::HTML::Div)
end
it "should return multple child elements" do
html = arbre do
div class: "some_class"
div class: "my_class"
div class: "my_class"
end
elements = html.get_elements_by_class_name("my_class")
expect(elements.size).to eq(2)
expect(elements[0]).to be_instance_of(Arbre::HTML::Div)
expect(elements[1]).to be_instance_of(Arbre::HTML::Div)
end
it "should return elements that match one of several classes" do
html = arbre do
div class: "some_class this_class"
div class: "some_class"
div class: "other_class"
end
elements = html.get_elements_by_class_name("this_class")
expect(elements.size).to eq(1)
expect(elements[0]).to be_instance_of(Arbre::HTML::Div)
end
it "should return a grandchild element" do
html = arbre do
div class: "some_class" do
div class: "my_class"
end
end
elements = html.get_elements_by_class_name("my_class")
expect(elements.size).to eq(1)
expect(elements[0]).to be_instance_of(Arbre::HTML::Div)
end
end
end
arbre-1.2.1/spec/spec_helper.rb 0000644 0001750 0001750 00000000157 13523740213 015715 0 ustar samyak samyak require 'support/bundle'
require 'arbre'
def arbre(&block)
Arbre::Context.new assigns, helpers, &block
end
arbre-1.2.1/Rakefile 0000644 0001750 0001750 00000000506 13523740213 013610 0 ustar samyak samyak require 'bundler'
Bundler::GemHelper.install_tasks
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec)
import 'tasks/lint.rake'
import 'tasks/release.rake'
task default: [:spec, :lint]
task :console do
require 'irb'
require 'irb/completion'
require 'pry'
require 'arbre'
ARGV.clear
IRB.start
end
arbre-1.2.1/README.md 0000644 0001750 0001750 00000003250 13523740213 013421 0 ustar samyak samyak # Arbre - HTML Views in Ruby
[Arbre][docs] makes it easy to generate HTML directly in Ruby. This gem was extracted from [Active Admin](https://github.com/activeadmin/active_admin).
[![Version ][rubygems_badge]][rubygems]
[![Travis CI ][travis_badge]][travis]
[![Tidelift ][tidelift_badge]][tidelift]
## Goals
The purpose of Arbre is to leave the view as ruby objects as long
as possible. This allows OO Design to be used to implement the view layer.
## Getting started
* Check out [the docs][docs].
## Need help?
Please use [StackOverflow][stackoverflow] for help requests and how-to questions.
Please open GitHub issues for bugs and enhancements only, not general help requests.
Please search previous issues (and Google and StackOverflow) before creating a new issue.
## Want to support us?
Subscribe to [Tidelift][tidelift] to support Arbre and get licensing assurances and timely security notifications.
## Security contact information
Please use the Tidelift security contact to [report a security vulnerability][Tidelift security contact].
Tidelift will coordinate the fix and disclosure.
[rubygems_badge]: http://img.shields.io/gem/v/arbre.svg
[rubygems]: https://rubygems.org/gems/arbre
[travis_badge]: http://img.shields.io/travis/activeadmin/arbre/master.svg
[travis]: https://travis-ci.org/activeadmin/arbre
[tidelift_badge]: https://tidelift.com/badges/github/activeadmin/arbre
[tidelift]: https://tidelift.com/subscription/pkg/rubygems-arbre?utm_source=rubygems-arbre&utm_medium=readme
[docs]: https://activeadmin.github.io/arbre/
[stackoverflow]: http://stackoverflow.com/questions/tagged/arbre
[Tidelift security contact]: https://tidelift.com/security
arbre-1.2.1/CHANGELOG.md 0000644 0001750 0001750 00000010274 13523740213 013757 0 ustar samyak samyak # Changelog
## Master (unreleased)
## 1.2.1 [☰](https://github.com/activeadmin/arbre/compare/v1.2.0...v1.2.1)
* Revert [#64][] to fix several regressions, at the cost of reintroducing [#46][]. [#121][] by [@deivid-rodriguez][]
## 1.2.0 [☰](https://github.com/activeadmin/arbre/compare/v1.2.0.rc1...v1.2.0)
_No changes_.
## 1.2.0.rc1 [☰](https://github.com/activeadmin/arbre/compare/v1.1.1...v1.2.0.rc1)
* Fix deprecation warning about single arity template handlers on Rails 6. [#110][] by [@aramvisser][]
* Fix rendering `link_to` with a block in a arbre template. [#64][] by [@varyonic][]
* Drop support for EOL'd rubies (under 2.3). [#78][] by [@deivid-rodriguez][]
## 1.1.1 [☰](https://github.com/activeadmin/arbre/compare/v1.1.0...v1.1.1)
* Use mime-types 2.x for Ruby 1.9 by [@timoschilling][]
* Verify Ruby 2.3 support. [#59][] by [@dlackty][]
## 1.1.0 [☰](https://github.com/activeadmin/arbre/compare/v1.0.3...v1.1.0)
* Tag option `for` sets the attribute when value is a string or symbol [#49][] by [@ramontayag][]
## 1.0.3 [☰](https://github.com/activeadmin/arbre/compare/v1.0.2...v1.0.3)
* Performance improvements [#40][] by [@alexesDev][]
* Added all void elements as self-closing tags [#39][] by [@OscarBarrett][]
* Missing tags added [#36][] / [#39][] by [@dtaniwaki][] and [@OscarBarrett][]
## 1.0.2 [☰](https://github.com/activeadmin/arbre/compare/v1.0.1...v1.0.2)
* make `Element#inspect` behave correctly in Ruby 2.0 [#16][] by [@seanlinsley][]
* prevent `Arbre::Element#flatten` infinite recursion [#32][] by [@seanlinsley][]
* make `find_by_class` correctly find children by class [#33][] by [@kaapa][]
## 1.0.1 [☰](https://github.com/activeadmin/arbre/compare/v1.0.0...v1.0.1)
* Template handler converts to string to satisfy Rack::Lint [#6][] by [@jpmckinney][]
* Fix to `Tag#add_class` when passing a string of classes to Tag build method
[#4][] by [@gregbell][]
* Not longer uses the default separator [#7][] by [@LTe][]
## 1.0.0 [☰](https://github.com/activeadmin/arbre/compare/v1.0.0.rc4...v1.0.0)
* Added support for the use of `:for` with non Active Model objects
## 1.0.0.rc4 [☰](https://github.com/activeadmin/arbre/compare/v1.0.0.rc3...v1.0.0.rc4)
* Fix issue where user could call `symbolize_keys!` on a
HashWithIndifferentAccess which doesn't implement the method
## 1.0.0.rc3 [☰](https://github.com/activeadmin/arbre/compare/v1.0.0.rc2...v1.0.0.rc3)
* Implemented `Arbre::HTML::Tag#default_id_for_prefix`
## 1.0.0.rc2 [☰](https://github.com/activeadmin/arbre/compare/v1.0.0.rc1...v1.0.0.rc2)
* Fixed bug where Component's build methods were being rendered within the
parent context.
## 1.0.0.rc1
Initial release and extraction from Active Admin
[#4]: https://github.com/activeadmin/arbre/issues/4
[#6]: https://github.com/activeadmin/arbre/issues/6
[#7]: https://github.com/activeadmin/arbre/issues/7
[#16]: https://github.com/activeadmin/arbre/issues/16
[#32]: https://github.com/activeadmin/arbre/issues/32
[#33]: https://github.com/activeadmin/arbre/issues/33
[#36]: https://github.com/activeadmin/arbre/issues/36
[#39]: https://github.com/activeadmin/arbre/issues/39
[#40]: https://github.com/activeadmin/arbre/issues/40
[#46]: https://github.com/activeadmin/arbre/issues/46
[#49]: https://github.com/activeadmin/arbre/issues/49
[#59]: https://github.com/activeadmin/arbre/issues/59
[#64]: https://github.com/activeadmin/arbre/pull/64
[#78]: https://github.com/activeadmin/arbre/pull/78
[#110]: https://github.com/activeadmin/arbre/pull/110
[#121]: https://github.com/activeadmin/arbre/pull/121
[@aramvisser]: https://github.com/aramvisser
[@LTe]: https://github.com/LTe
[@OscarBarrett]: https://github.com/OscarBarrett
[@alexesDev]: https://github.com/alexesDev
[@deivid-rodriguez]: https://github.com/deivid-rodriguez
[@dlackty]: https://github.com/dlackty
[@dtaniwaki]: https://github.com/dtaniwaki
[@gregbell]: https://github.com/gregbell
[@jpmckinney]: https://github.com/jpmckinney
[@kaapa]: https://github.com/kaapa
[@ramontayag]: https://github.com/ramontayag
[@seanlinsley]: https://github.com/seanlinsley
[@timoschilling]: https://github.com/timoschilling
[@varyonic]: https://github.com/varyonic