Skip to content

Commit

Permalink
First actual import of code from Active Admin
Browse files Browse the repository at this point in the history
  • Loading branch information
gregbell committed Feb 17, 2012
1 parent cb76420 commit 7834b7a
Show file tree
Hide file tree
Showing 26 changed files with 1,543 additions and 2 deletions.
Binary file added .DS_Store
Binary file not shown.
4 changes: 4 additions & 0 deletions Gemfile
Expand Up @@ -2,3 +2,7 @@ source "http://rubygems.org"

# Specify your gem's dependencies in arbre.gemspec
gemspec

group :test do
gem "rspec"
end
35 changes: 33 additions & 2 deletions README.rdoc
@@ -1,3 +1,34 @@
Arbre - Coming Soon. For now, checkout Active Admin:
= Arbre - Ruby Object Oriented HTML Views

http://github.com/gregbell/active_admin
Arbre is the DOM implemented in Ruby. This project is primarily used as
the object oriented view layer in Active Admin.

== Simple Usage

A simple example of setting up an Arbre context and creating some html

html = Arbre::Context.new do
h2 "Why Arbre is awesome?"

ul do
li "The DOM is implemented in ruby"
li "You can create object oriented views"
li "Templates suck"
end
end

puts html.to_s #=> <h2>Why</h2><ul><li></li></ul>


== The DOM in Ruby

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.


html = Arbre::Context.new do
h2 "Why Arbre is awesome?"
end

html.children.size #=> 1
html.children.first #=> #<Arbre::HTML::H2>
2 changes: 2 additions & 0 deletions arbre.gemspec
Expand Up @@ -16,4 +16,6 @@ Gem::Specification.new do |s|
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.add_dependency("activesupport", ">= 3.0.0")
end
Binary file added lib/.DS_Store
Binary file not shown.
13 changes: 13 additions & 0 deletions lib/arbre.rb
@@ -1,2 +1,15 @@
require 'active_support/core_ext/string/output_safety'
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'
80 changes: 80 additions & 0 deletions lib/arbre/builder.rb
@@ -0,0 +1,80 @@
module Arbre

# Include this module in any context to start building html.
#
# assigns = {}
# include Arbre::Builder
# span("foo").to_s #=> "<span>foo</span>
#
# When you include the module, you are required to setup 2 variables:
#
# * assigns: This is a hash that includes local variables
# * helpers: This is an object that provides helper methods to all
# objects within the context.
module Builder

module BuilderMethods
def build_tag(klass, *args, &block)
tag = klass.new(assigns, helpers)
tag.parent = current_dom_context

# If you passed in a block and want the object
if block_given? && block.arity > 0
# Set out context to the tag, and pass responsibility to the tag
with_current_dom_context tag do
tag.build(*args, &block)
end
else
# Build the tag
tag.build(*args)

# Render the blocks contents
if block_given?
with_current_dom_context tag do
append_return_block(yield)
end
end
end

tag
end

def insert_tag(klass, *args, &block)
tag = build_tag(klass, *args, &block)
current_dom_context.add_child(tag)
tag
end

def current_dom_context
@__current_dom_element_buffer__ ||= [self]
current_element = @__current_dom_element_buffer__.last
if current_element == self
self
else
current_element.current_dom_context
end
end

def with_current_dom_context(tag)
raise ArgumentError, "Can't be in the context of nil. #{@__current_dom_element_buffer__.inspect}" unless tag
current_dom_context # Ensure a context is setup
@__current_dom_element_buffer__.push tag
yield
@__current_dom_element_buffer__.pop
end
alias_method :within, :with_current_dom_context

# 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_dom_context.children?

if !tag.is_a?(Arbre::Element) && tag.respond_to?(:to_s)
current_dom_context << Arbre::HTML::TextNode.from_string(tag.to_s)
end
end
end

end
end

22 changes: 22 additions & 0 deletions lib/arbre/component.rb
@@ -0,0 +1,22 @@
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
52 changes: 52 additions & 0 deletions lib/arbre/context.rb
@@ -0,0 +1,52 @@
require 'arbre/element'

module Arbre
class Context < Element

def initialize(assigns = {}, helpers = nil, &block)
assigns.symbolize_keys!
super(assigns, helpers)
instance_eval &block
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?(method)
super || cached_html.respond_to?(method)
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

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

0 comments on commit 7834b7a

Please sign in to comment.