abstract_interface 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +64 -0
- data/lib/abstract_interface/abstract_interface.rb +64 -0
- data/lib/abstract_interface/controller_helper.rb +24 -0
- data/lib/abstract_interface/haml_builder.rb +56 -0
- data/lib/abstract_interface/support.rb +40 -0
- data/lib/abstract_interface/theme.rb +37 -0
- data/lib/abstract_interface/themed_form_helper.rb +74 -0
- data/lib/abstract_interface/view_builder.rb +100 -0
- data/lib/abstract_interface/view_helper.rb +42 -0
- data/lib/abstract_interface.rb +25 -0
- data/readme.md +3 -0
- data/spec/haml_builder_spec.rb +121 -0
- data/spec/helper.rb +9 -0
- data/spec/spec.opts +4 -0
- metadata +93 -0
data/Rakefile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'fileutils'
|
3
|
+
current_dir = File.expand_path(File.dirname(__FILE__))
|
4
|
+
Dir.chdir current_dir
|
5
|
+
|
6
|
+
|
7
|
+
#
|
8
|
+
# Specs
|
9
|
+
#
|
10
|
+
require 'spec/rake/spectask'
|
11
|
+
|
12
|
+
task :default => :spec
|
13
|
+
|
14
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
15
|
+
t.spec_files = FileList["spec/**/*_spec.rb"].select{|f| f !~ /\/_/}
|
16
|
+
t.libs = ["#{current_dir}/lib"]
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
#
|
21
|
+
# Gem
|
22
|
+
#
|
23
|
+
require 'rake/clean'
|
24
|
+
require 'rake/gempackagetask'
|
25
|
+
|
26
|
+
gem_options = {
|
27
|
+
:name => "abstract_interface",
|
28
|
+
:version => "0.1.0",
|
29
|
+
:summary => "Ruby language extensions",
|
30
|
+
:dependencies => %w(facets)
|
31
|
+
}
|
32
|
+
|
33
|
+
spec = Gem::Specification.new do |s|
|
34
|
+
gem_options.delete(:dependencies).each{|d| s.add_dependency d}
|
35
|
+
gem_options.each{|k, v| s.send "#{k}=", v}
|
36
|
+
|
37
|
+
s.author = "Alexey Petrushin"
|
38
|
+
s.homepage = "http://github.com/alexeypetrushin/#{gem_options[:name]}"
|
39
|
+
s.require_path = "lib"
|
40
|
+
s.files = (%w{Rakefile readme.md} + Dir.glob("{lib,spec}/**/*"))
|
41
|
+
|
42
|
+
s.platform = Gem::Platform::RUBY
|
43
|
+
s.has_rdoc = true
|
44
|
+
end
|
45
|
+
|
46
|
+
package_dir = "#{current_dir}/build"
|
47
|
+
Rake::GemPackageTask.new(spec) do |p|
|
48
|
+
p.need_tar = true if RUBY_PLATFORM !~ /mswin/
|
49
|
+
p.need_zip = true
|
50
|
+
p.package_dir = package_dir
|
51
|
+
end
|
52
|
+
|
53
|
+
task :push do
|
54
|
+
# dir = Dir.chdir package_dir do
|
55
|
+
gem_file = Dir.glob("#{package_dir}/#{gem_options[:name]}*.gem").first
|
56
|
+
system "gem push #{gem_file}"
|
57
|
+
# end
|
58
|
+
end
|
59
|
+
|
60
|
+
task :clean do
|
61
|
+
system "rm -r #{package_dir}"
|
62
|
+
end
|
63
|
+
|
64
|
+
task :release => [:gem, :push, :clean]
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module AbstractInterface
|
2
|
+
class << self
|
3
|
+
inject :logger => :logger, :config => :config, :environment => :environment
|
4
|
+
|
5
|
+
attr_accessor :plugin_name
|
6
|
+
attr_accessor :layout_configurations_dir
|
7
|
+
|
8
|
+
def generate_helper_methods *args
|
9
|
+
AbstractInterface::ViewBuilder.generate_helper_methods *args
|
10
|
+
end
|
11
|
+
|
12
|
+
def available_themes; @available_themes ||= [] end
|
13
|
+
|
14
|
+
def theme_metadata theme
|
15
|
+
logger.warn "Complex calculation (AbstractInterface.theme_metadata) called in production!" if config.production?
|
16
|
+
|
17
|
+
metadata = {}
|
18
|
+
|
19
|
+
name = "/#{Crystal::Template::DIRECTORY_NAME}/#{THEMES_DIR}/#{theme}/metadata.rb"
|
20
|
+
if environment.file_exist? name
|
21
|
+
fname = environment.find_file name
|
22
|
+
code = File.read fname
|
23
|
+
metadata = eval code
|
24
|
+
metadata.must_be.a Hash
|
25
|
+
end
|
26
|
+
|
27
|
+
metadata.to_openobject
|
28
|
+
end
|
29
|
+
|
30
|
+
def layouts_defined?
|
31
|
+
!!layout_configurations_dir
|
32
|
+
end
|
33
|
+
|
34
|
+
# Place definitions of your layouts into :layout_configurations_dir folder, you can have multiple such directories
|
35
|
+
def layout_definitions_without_cache theme
|
36
|
+
name = "#{layout_configurations_dir.must_be.present}/#{theme}.yml"
|
37
|
+
raise "File '#{name}' not exist!" unless environment.file_exist? name
|
38
|
+
|
39
|
+
result = {}
|
40
|
+
environment.find_files(name).each do |fname|
|
41
|
+
lds = YAML.load_file(fname)
|
42
|
+
validate_layout_definition!(lds, theme)
|
43
|
+
result.merge! lds
|
44
|
+
end
|
45
|
+
result
|
46
|
+
end
|
47
|
+
cache_method_with_params_in_production :layout_definitions
|
48
|
+
|
49
|
+
protected
|
50
|
+
def validate_layout_definition! lds, theme
|
51
|
+
lds.must_be.a Hash
|
52
|
+
unless lds.include?('default')
|
53
|
+
raise "No 'default' layout definition for '#{theme}' Theme (there always should be definition for 'default' layout)!"
|
54
|
+
end
|
55
|
+
lds.each do |theme_name, ld|
|
56
|
+
ld.must_be.a Hash
|
57
|
+
ld.must.include 'layout_template'
|
58
|
+
ld.must.include 'slots'
|
59
|
+
ld['slots'].must_be.a Hash
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module AbstractInterface
|
2
|
+
module ControllerHelper
|
3
|
+
def current_theme
|
4
|
+
@current_theme ||= AbstractInterface::Theme.new
|
5
|
+
end
|
6
|
+
|
7
|
+
# TODO1
|
8
|
+
# def build_layout layout = nil
|
9
|
+
# # Configuring
|
10
|
+
# current_theme.layout = layout
|
11
|
+
#
|
12
|
+
# # Rendering
|
13
|
+
# current_theme.layout_definition['slots'].each do |slot_name, slots|
|
14
|
+
# slots = Array(slots)
|
15
|
+
# slots.each do |partial|
|
16
|
+
# content_for slot_name do
|
17
|
+
# render :partial => partial
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module AbstractInterface
|
2
|
+
class HamlBuilder < BasicObject
|
3
|
+
def initialize template, hash = OpenObject.new
|
4
|
+
@template = template
|
5
|
+
@hash, @array = hash, []
|
6
|
+
end
|
7
|
+
|
8
|
+
def method_missing m, value = nil, &block
|
9
|
+
@hash[m] = HamlBuilder.get_input @template, value, &block
|
10
|
+
nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def add value = nil, &block
|
14
|
+
@array << HamlBuilder.get_input(@template, value, &block)
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
# def add_item content, opt = {}, &block
|
19
|
+
# opt[:content] = content
|
20
|
+
# opt[:content] ||= @template.capture &block if block
|
21
|
+
# add opt
|
22
|
+
# end
|
23
|
+
|
24
|
+
def get_value
|
25
|
+
!@array.empty? ? @array : @hash
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.get_input template, value, &block
|
29
|
+
value = value.to_openobject if value.is_a? Hash
|
30
|
+
|
31
|
+
block_value = if block
|
32
|
+
if block.arity <= 0
|
33
|
+
template.must_be.defined
|
34
|
+
template.capture &block
|
35
|
+
else
|
36
|
+
b = HamlBuilder.new template
|
37
|
+
block.call b
|
38
|
+
b.get_value
|
39
|
+
end
|
40
|
+
else
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
|
44
|
+
if value and block_value
|
45
|
+
if block_value.is_a? Hash
|
46
|
+
value = value.merge block_value
|
47
|
+
else
|
48
|
+
raise "Invalid usage!" if value.include? :content
|
49
|
+
value.content = block_value
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
value || block_value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# content_or_self
|
2
|
+
[Hash, OpenObject].each do |aclass|
|
3
|
+
aclass.class_eval do
|
4
|
+
def hash?; true end
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
NilClass.class_eval do
|
9
|
+
def content; "" end
|
10
|
+
def hash?; false end
|
11
|
+
end
|
12
|
+
|
13
|
+
String.class_eval do
|
14
|
+
def content; self end
|
15
|
+
def hash?; false end
|
16
|
+
end
|
17
|
+
|
18
|
+
# OpenObject
|
19
|
+
OpenObject.class_eval do
|
20
|
+
HTML_ATTRIBUTES = [:id, :class]
|
21
|
+
|
22
|
+
def merge_html_attributes hash
|
23
|
+
# html attributes
|
24
|
+
result = {}
|
25
|
+
HTML_ATTRIBUTES.each{|k| result[k.to_s] = self[k] if include? k}
|
26
|
+
html_attributes.each{|k, v| result[k.to_s] = v} if html_attributes?
|
27
|
+
|
28
|
+
# merging html attributes with hash
|
29
|
+
hash.each do |k, v|
|
30
|
+
k = k.to_s
|
31
|
+
if result.include?(k) and v.is_a?(String)
|
32
|
+
string = result[k].must_be.a [Symbol, String]
|
33
|
+
result[k] = "#{result[k]}#{v}"
|
34
|
+
else
|
35
|
+
result[k] = v
|
36
|
+
end
|
37
|
+
end
|
38
|
+
result
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module AbstractInterface
|
2
|
+
class Theme
|
3
|
+
attr_writer :name, :layout_template, :layout
|
4
|
+
def name; @name || 'default' end
|
5
|
+
def layout; @layout || 'default' end
|
6
|
+
|
7
|
+
def layout_template
|
8
|
+
if @layout_template
|
9
|
+
# Check if this template exists
|
10
|
+
exists = layout_definitions.any?{|layout_name, ld| ld['layout_template'] == @layout_template}
|
11
|
+
exists ? @layout_template : 'default'
|
12
|
+
else
|
13
|
+
layout_definition['layout_template'] || 'default'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def layout_definition
|
18
|
+
layout_definitions[layout] || layout_definitions['default'] || {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def layout_definitions
|
22
|
+
if AbstractInterface.layouts_defined?
|
23
|
+
AbstractInterface.layout_definitions(name)
|
24
|
+
else
|
25
|
+
{}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def available_layouts_names
|
30
|
+
layout_definitions.keys
|
31
|
+
end
|
32
|
+
|
33
|
+
def metadata
|
34
|
+
AbstractInterface.theme_metadata(name)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module AbstractInterface
|
2
|
+
class ThemedFormHelper
|
3
|
+
attr_accessor :template
|
4
|
+
|
5
|
+
def initialize template
|
6
|
+
self.template = template
|
7
|
+
end
|
8
|
+
|
9
|
+
def error_messages *errors
|
10
|
+
errors = errors.first if errors.size == 1 and errors.first.is_a? Array
|
11
|
+
template.render template.themed_partial('forms/errors'), :object => errors
|
12
|
+
end
|
13
|
+
|
14
|
+
def form_field options, &block
|
15
|
+
html_options = options.to_openobject
|
16
|
+
options = OpenObject.new
|
17
|
+
|
18
|
+
# prepare options
|
19
|
+
%w(errors label description required theme).each do |k|
|
20
|
+
v = html_options.delete k
|
21
|
+
options[k] = v unless v.nil?
|
22
|
+
end
|
23
|
+
options.errors = options.errors.to_a
|
24
|
+
|
25
|
+
# CSS style
|
26
|
+
html_options.class ||= ""
|
27
|
+
html_options << " themed_input"
|
28
|
+
|
29
|
+
options.content = template.capture{block.call(html_options)}
|
30
|
+
|
31
|
+
html = template.render(template.themed_partial('forms/field'), :object => options)
|
32
|
+
template.concat html
|
33
|
+
end
|
34
|
+
|
35
|
+
def line *items
|
36
|
+
template.render template.themed_partial('forms/line'), :object => {:items => items, :delimiter => false}.to_openobject
|
37
|
+
end
|
38
|
+
|
39
|
+
def line_with_delimiters *items
|
40
|
+
template.render template.themed_partial('forms/line'), :object => {:items => items, :delimiter => true}.to_openobject
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
#
|
45
|
+
# Form fields
|
46
|
+
#
|
47
|
+
%w(
|
48
|
+
check_box_tag
|
49
|
+
field_set_tag
|
50
|
+
file_field_tag
|
51
|
+
password_field_tag
|
52
|
+
radio_button_tag
|
53
|
+
select_tag
|
54
|
+
text_field_tag
|
55
|
+
text_area_tag
|
56
|
+
).each do |m|
|
57
|
+
define_method m do |*args|
|
58
|
+
options = args.extract_options!
|
59
|
+
template.capture do
|
60
|
+
form_field options do |html_options|
|
61
|
+
args << html_options
|
62
|
+
template.concat(template.send(m, *args))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
%w(
|
69
|
+
hidden_field_tag
|
70
|
+
submit_tag
|
71
|
+
).each{|m| delegate m, :to => :template}
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module AbstractInterface
|
2
|
+
class ViewBuilder
|
3
|
+
|
4
|
+
def self.generate_helper_methods methods
|
5
|
+
methods.each do |folder, templates|
|
6
|
+
templates.each do |template|
|
7
|
+
code = %{\
|
8
|
+
def #{template} *args, &block
|
9
|
+
render_haml_builder "#{folder}", "#{template}", *args, &block
|
10
|
+
end}
|
11
|
+
|
12
|
+
eval code, binding, __FILE__, __LINE__
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
attr_reader :template
|
19
|
+
def initialize template
|
20
|
+
@template = template
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
#
|
25
|
+
# Template methods
|
26
|
+
#
|
27
|
+
%w(
|
28
|
+
capture
|
29
|
+
concat
|
30
|
+
content_for
|
31
|
+
tag
|
32
|
+
render
|
33
|
+
themed_resource
|
34
|
+
themed_partial
|
35
|
+
controller
|
36
|
+
).each do |m|
|
37
|
+
delegate m, :to => :template
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
#
|
42
|
+
# Builders
|
43
|
+
#
|
44
|
+
def options *args, &block
|
45
|
+
opt = args.extract_options!
|
46
|
+
args.size.must_be.in 0..1
|
47
|
+
opt[:content] = args.first if args.size == 1
|
48
|
+
|
49
|
+
AbstractInterface::HamlBuilder.get_input self.template, opt, &block
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
#
|
54
|
+
# Forms
|
55
|
+
#
|
56
|
+
def form_tag *args, &block
|
57
|
+
f = ThemedFormHelper.new(template)
|
58
|
+
|
59
|
+
content = block ? capture{block.call(f)} : ""
|
60
|
+
html = render(
|
61
|
+
themed_partial('forms/form'),
|
62
|
+
:object => {:form_attributes => options, :content => content}.to_openobject
|
63
|
+
)
|
64
|
+
|
65
|
+
if block
|
66
|
+
template.concat html
|
67
|
+
else
|
68
|
+
html
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def form_for *args, &block
|
73
|
+
model_helper, options = template.build_form_model_helper_and_form_options *args
|
74
|
+
|
75
|
+
form_tag options do |themed_form_helper|
|
76
|
+
model_helper.form_helper = themed_form_helper
|
77
|
+
|
78
|
+
block.call model_helper if block
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def render_haml_builder folder, template, *args, &block
|
85
|
+
opt = options *args, &block
|
86
|
+
|
87
|
+
partial = "#{folder}/#{template}"
|
88
|
+
|
89
|
+
html = render themed_partial(partial), :object => opt
|
90
|
+
|
91
|
+
block ? self.concat(html) : html
|
92
|
+
end
|
93
|
+
|
94
|
+
def prepare_form! options, *args
|
95
|
+
buff = template.form_tag *args
|
96
|
+
options[:begin] = buff
|
97
|
+
options[:end] = '</form>'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module AbstractInterface
|
2
|
+
module ViewHelper
|
3
|
+
def b
|
4
|
+
@b ||= AbstractInterface::ViewBuilder.new self
|
5
|
+
end
|
6
|
+
alias_method :builder, :b
|
7
|
+
|
8
|
+
def themed_resource resource
|
9
|
+
"/#{AbstractInterface.plugin_name.must_not_be.blank}/#{THEMES_DIR}/#{current_theme.name}/#{resource}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def themed_partial partial
|
13
|
+
themed_partial = "/#{THEMES_DIR}/#{current_theme.name}/#{partial}"
|
14
|
+
if Crystal::Template.exist? themed_partial
|
15
|
+
themed_partial
|
16
|
+
else
|
17
|
+
"/#{THEMES_DIR}/default/#{partial}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def current_theme
|
22
|
+
controller.current_theme
|
23
|
+
end
|
24
|
+
|
25
|
+
# TODO1
|
26
|
+
# def build_layout layout = nil
|
27
|
+
# # Configuring
|
28
|
+
# current_theme.layout = layout
|
29
|
+
#
|
30
|
+
# # Rendering
|
31
|
+
# current_theme.layout_definition['slots'].each do |slot_name, slots|
|
32
|
+
# slots = Array(slots)
|
33
|
+
# slots.each do |partial|
|
34
|
+
# content_for slot_name do
|
35
|
+
# render :partial => partial
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'abstract_interface/support'
|
2
|
+
|
3
|
+
module AbstractInterface
|
4
|
+
THEMES_DIR = 'themes'
|
5
|
+
|
6
|
+
autoload :Theme, 'abstract_interface/theme'
|
7
|
+
autoload :HamlBuilder, 'abstract_interface/haml_builder'
|
8
|
+
autoload :ThemedFormHelper, 'abstract_interface/themed_form_helper'
|
9
|
+
autoload :ViewBuilder, 'abstract_interface/view_builder'
|
10
|
+
autoload :ViewHelper, 'abstract_interface/view_helper'
|
11
|
+
autoload :ControllerHelper, 'abstract_interface/controller_helper'
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'abstract_interface/abstract_interface'
|
15
|
+
|
16
|
+
Crystal::ControllerContext.inherit AbstractInterface::ViewHelper
|
17
|
+
Crystal::AbstractController.inherit AbstractInterface::ControllerHelper
|
18
|
+
|
19
|
+
# TODO2
|
20
|
+
# ActionView::Base.field_error_proc = lambda do |html_tag, instance|
|
21
|
+
# html_tag
|
22
|
+
# end
|
23
|
+
|
24
|
+
# TODO1
|
25
|
+
# Rails.development{RailsExt.create_public_symlinks!} # rails_ext.css, rails_ext.js in development mode
|
data/readme.md
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
dir = File.expand_path(File.dirname(__FILE__))
|
2
|
+
require "#{dir}/helper"
|
3
|
+
|
4
|
+
#
|
5
|
+
# Don't use should ==, it doesn't works with OpenObject
|
6
|
+
#
|
7
|
+
describe "HamlBuilder use cases" do
|
8
|
+
class TemplateStub
|
9
|
+
def self.capture &block
|
10
|
+
block.call
|
11
|
+
self.output
|
12
|
+
end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
attr_accessor :output
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def build *args, &block
|
20
|
+
opt = args.extract_options!
|
21
|
+
args.size.must_be.in 0..1
|
22
|
+
opt[:content] = args.first if args.size == 1
|
23
|
+
|
24
|
+
AbstractInterface::HamlBuilder.get_input(TemplateStub, opt, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should accept OpenObject as input" do
|
28
|
+
build({:a => :b}.to_openobject).should == {:a => :b}
|
29
|
+
end
|
30
|
+
|
31
|
+
it "hash" do
|
32
|
+
(build do |o|
|
33
|
+
o.a :b
|
34
|
+
end).should == {:a => :b}
|
35
|
+
|
36
|
+
build(:a => :b).should == {:a => :b}
|
37
|
+
end
|
38
|
+
|
39
|
+
it "array" do
|
40
|
+
(build do |a|
|
41
|
+
a.add 1
|
42
|
+
a.add 2
|
43
|
+
end).should == {:content => [1, 2]}
|
44
|
+
|
45
|
+
(build do |o|
|
46
|
+
o.a :b
|
47
|
+
o.ar do |a|
|
48
|
+
a.add 1
|
49
|
+
a.add 2
|
50
|
+
end
|
51
|
+
end).should == {:a => :b, :ar => [1, 2]}
|
52
|
+
end
|
53
|
+
|
54
|
+
it "capture" do
|
55
|
+
build("value").should == {:content => "value"}
|
56
|
+
|
57
|
+
(build do
|
58
|
+
TemplateStub.output = "value"
|
59
|
+
end).should == {:content => "value"}
|
60
|
+
|
61
|
+
(build do |o|
|
62
|
+
o.content do
|
63
|
+
TemplateStub.output = "value"
|
64
|
+
end
|
65
|
+
end).should == {:content => "value"}
|
66
|
+
|
67
|
+
(build do |o|
|
68
|
+
o.value do
|
69
|
+
TemplateStub.output = "value"
|
70
|
+
end
|
71
|
+
end).should == {:value => "value"}
|
72
|
+
end
|
73
|
+
|
74
|
+
it "invalid usage" do
|
75
|
+
lambda{
|
76
|
+
build "value" do
|
77
|
+
TemplateStub.output = "value"
|
78
|
+
end
|
79
|
+
}.should raise_error(/Invalid usage!/)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "merge" do
|
83
|
+
(build :a => :b do
|
84
|
+
TemplateStub.output = "value"
|
85
|
+
end).should == {:a => :b, :content => "value"}
|
86
|
+
|
87
|
+
(build :a => :b do |o|
|
88
|
+
o.c :d
|
89
|
+
end).should == {:a => :b, :c => :d}
|
90
|
+
end
|
91
|
+
|
92
|
+
it "nested" do
|
93
|
+
(build :a => :b do |o|
|
94
|
+
o.a do |o|
|
95
|
+
o.b :c
|
96
|
+
end
|
97
|
+
end).should == {
|
98
|
+
:a => {:b => :c}
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
it "complex" do
|
103
|
+
(build :a => :b do |o|
|
104
|
+
o.hs do |h|
|
105
|
+
h.c :d
|
106
|
+
end
|
107
|
+
o.ar do |a|
|
108
|
+
a.add 1
|
109
|
+
a.add 2
|
110
|
+
end
|
111
|
+
o.html do
|
112
|
+
TemplateStub.output = "value"
|
113
|
+
end
|
114
|
+
end).should == {
|
115
|
+
:a => :b,
|
116
|
+
:hs => {:c => :d},
|
117
|
+
:ar => [1, 2],
|
118
|
+
:html => 'value'
|
119
|
+
}
|
120
|
+
end
|
121
|
+
end
|
data/spec/helper.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
dir = File.expand_path(File.dirname(__FILE__))
|
2
|
+
lib_dir = File.expand_path("#{dir}/../../../lib")
|
3
|
+
$LOAD_PATH << lib_dir unless $LOAD_PATH.include? lib_dir
|
4
|
+
|
5
|
+
require 'crystal/support'
|
6
|
+
require 'abstract_interface/support'
|
7
|
+
require "abstract_interface/haml_builder"
|
8
|
+
|
9
|
+
require 'spec_ext'
|
data/spec/spec.opts
ADDED
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: abstract_interface
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Alexey Petrushin
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-11 00:00:00 +04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: facets
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
description:
|
36
|
+
email:
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- Rakefile
|
45
|
+
- readme.md
|
46
|
+
- lib/abstract_interface/abstract_interface.rb
|
47
|
+
- lib/abstract_interface/controller_helper.rb
|
48
|
+
- lib/abstract_interface/haml_builder.rb
|
49
|
+
- lib/abstract_interface/support.rb
|
50
|
+
- lib/abstract_interface/theme.rb
|
51
|
+
- lib/abstract_interface/themed_form_helper.rb
|
52
|
+
- lib/abstract_interface/view_builder.rb
|
53
|
+
- lib/abstract_interface/view_helper.rb
|
54
|
+
- lib/abstract_interface.rb
|
55
|
+
- spec/haml_builder_spec.rb
|
56
|
+
- spec/helper.rb
|
57
|
+
- spec/spec.opts
|
58
|
+
has_rdoc: true
|
59
|
+
homepage: http://github.com/alexeypetrushin/abstract_interface
|
60
|
+
licenses: []
|
61
|
+
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
hash: 3
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
version: "0"
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
hash: 3
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
version: "0"
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 1.3.7
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: Ruby language extensions
|
92
|
+
test_files: []
|
93
|
+
|