rad_face 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'rake_ext'
2
+
3
+ project(
4
+ name: "face",
5
+ official_name: "rad_face",
6
+ gem: true,
7
+ summary: "User Interface tools for Rad Framework",
8
+
9
+ author: "Alexey Petrushin",
10
+ homepage: "http://github.com/alexeypetrushin/rad_face"
11
+ )
@@ -0,0 +1,5 @@
1
+ rad.register :face, depends_on: [:controller, :template, :js, :web, :assets] do
2
+ require 'face/gems'
3
+ require 'face/require'
4
+ Rad::Face.new
5
+ end
@@ -0,0 +1,2 @@
1
+ themes_path: '/themes'
2
+ available_themes: []
@@ -0,0 +1,3 @@
1
+ rad.register :theme, depends_on: :face, scope: :cycle do
2
+ Rad::Face::Theme.new
3
+ end
data/lib/face/face.rb ADDED
@@ -0,0 +1,9 @@
1
+ class Rad::Face
2
+ attr_accessor :themes_path, :theme, :available_themes
3
+ require_attr :themes_path
4
+ def available_themes; @available_themes ||= [] end
5
+
6
+ def availiable_layouts
7
+ @availiable_layouts ||= {}
8
+ end
9
+ end
data/lib/face/gems.rb ADDED
@@ -0,0 +1,6 @@
1
+ if respond_to? :fake_gem
2
+ fake_gem 'rad_core'
3
+ fake_gem 'rad_ext'
4
+ fake_gem 'rad_js'
5
+ fake_gem 'rad_assets'
6
+ end
@@ -0,0 +1,49 @@
1
+ class Rad::Face::HamlBuilder < BasicObject
2
+ def initialize template, hash = {}
3
+ @template = template
4
+ @hash = ::Rad::Face::HtmlOpenObject.initialize_from(hash)
5
+ @array = []
6
+ end
7
+
8
+ def method_missing m, value = nil, &block
9
+ @hash[m] = ::Rad::Face::HamlBuilder.get_input @template, value, &block
10
+ nil
11
+ end
12
+
13
+ def add value = nil, &block
14
+ @array << ::Rad::Face::HamlBuilder.get_input(@template, value, &block)
15
+ nil
16
+ end
17
+
18
+ def get_value
19
+ !@array.empty? ? @array : @hash
20
+ end
21
+
22
+ def self.get_input template, value, &block
23
+ value = ::Rad::Face::HtmlOpenObject.initialize_from(value) if value.is_a? ::Hash
24
+
25
+ block_value = if block
26
+ if block.arity <= 0
27
+ template.must_be.defined
28
+ template.capture &block
29
+ else
30
+ b = ::Rad::Face::HamlBuilder.new template
31
+ block.call b
32
+ b.get_value
33
+ end
34
+ else
35
+ nil
36
+ end
37
+
38
+ if value and block_value
39
+ if block_value.is_a? ::Hash
40
+ value.merge! block_value
41
+ else
42
+ raise "Invalid usage!" if value.include? :content
43
+ value.content = block_value
44
+ end
45
+ end
46
+
47
+ value || block_value
48
+ end
49
+ end
@@ -0,0 +1,54 @@
1
+ class Rad::Face::HtmlOpenObject < OpenObject
2
+ HTML_ATTRIBUTES = [:id, :class]
3
+
4
+ def merge_html_attributes hash = {}
5
+ # html attributes
6
+ result = {}
7
+ HTML_ATTRIBUTES.each{|k| result[k.to_s] = self[k] if include? k}
8
+ html_attributes.each{|k, v| result[k.to_s] = v} if html_attributes?
9
+
10
+ # merging html attributes with hash
11
+ hash.each do |k, v|
12
+ k = k.to_s
13
+ if result.include?(k) and v.is_a?(String)
14
+ string = result[k].must_be.a Symbol, String
15
+ result[k] = "#{result[k]}#{v}"
16
+ else
17
+ result[k] = v
18
+ end
19
+ end
20
+ result
21
+ end
22
+
23
+ def self.initialize_from hash, deep = false
24
+ unless deep
25
+ ::Rad::Face::HtmlOpenObject.new.update hash
26
+ else
27
+ r = ::Rad::Face::HtmlOpenObject.new
28
+ hash.each do |k, v|
29
+ r[k] = if v.is_a? Hash
30
+ v.to_openobject
31
+ else
32
+ v
33
+ end
34
+ end
35
+ r
36
+ end
37
+ end
38
+
39
+ protected
40
+ # should threat newlines as blank
41
+ def method_missing m, arg = nil, &block
42
+ type = m[-1,1]
43
+ if type == '='
44
+ self[m[0..-2]] = arg
45
+ elsif type == '!'
46
+ self[m[0..-2]]
47
+ elsif type == '?'
48
+ value = self[m[0..-2]]
49
+ !(value.is_a?(String) ? (value =~ /\A\s*\z/) : value.blank?)
50
+ else
51
+ self[m]
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,18 @@
1
+ require 'rad_ext'
2
+
3
+ class Rad::Face
4
+ end
5
+
6
+ %w(
7
+ support
8
+ html_open_object
9
+ theme
10
+ haml_builder
11
+ themed_form_helper
12
+ view_builder
13
+ view_helper
14
+ face
15
+ ).each{|f| require "face/#{f}"}
16
+
17
+ Rad::Template::Context.inherit Rad::Face::ViewHelper
18
+ Rad::Controller::Abstract.inject theme: :theme
@@ -0,0 +1,42 @@
1
+ #
2
+ # content_or_self
3
+ #
4
+ [Hash, OpenObject].each do |aclass|
5
+ aclass.class_eval do
6
+ def hash?; true end
7
+ end
8
+ end
9
+
10
+ NilClass.class_eval do
11
+ def content; "" end
12
+ def hash?; false end
13
+ end
14
+
15
+ String.class_eval do
16
+ def content; self end
17
+ def hash?; false end
18
+ end
19
+
20
+ # OpenObject
21
+ OpenObject.class_eval do
22
+ def merge_html_attributes *a
23
+ raise "invalid usage, something wrong goin on, this method should be called only from instance of HtmlOpenObject class!"
24
+ end
25
+ alias_method :merge_html_attributes?, :merge_html_attributes
26
+ alias_method :merge_html_attributes!, :merge_html_attributes
27
+ end
28
+
29
+
30
+ #
31
+ # Automaticaly add content of action view to the :content content variable,
32
+ # to eliminate need for "content_for :content do ..." stuff.
33
+ #
34
+ Rad::Controller::Abstract::Render.class_eval do
35
+ protected
36
+ def render_content_with_content *a
37
+ content, context = render_content_without_content *a
38
+ context.content_for :content, content
39
+ return content, context
40
+ end
41
+ alias_method_chain :render_content, :content
42
+ end
data/lib/face/theme.rb ADDED
@@ -0,0 +1,48 @@
1
+ class Rad::Face::Theme
2
+ def name; @name || 'default' end
3
+ def name= name
4
+ # lots of other properties depends on :name, so we need to clean all of them if we change name
5
+ clear
6
+ @name = name.to_sym if name.present?
7
+ end
8
+
9
+ attr_writer :layout
10
+ def layout; @layout || 'default' end
11
+
12
+ def layout_template
13
+ @layout_template || layout_definition['layout_template'] || 'default'
14
+ end
15
+
16
+ def layout_template= layout_template
17
+ path = "#{rad.face.themes_path}/#{name}/layout_templates/#{layout_template}"
18
+ @layout_template = (layout_template and rad.template.exist?(path)) ? layout_template : 'default'
19
+ end
20
+
21
+ def layout_definition
22
+ self.class.layout_definition(name, layout) || self.class.layout_definition(name, 'default') || {}
23
+ end
24
+
25
+ protected
26
+ def clear
27
+ @layout_config, @layout_template, @layout = nil
28
+ end
29
+
30
+ class << self
31
+ def layout_definition theme, layout
32
+ path = "#{rad.face.themes_path}/#{theme}/layout_definitions/#{layout}.yml"
33
+ files = Rad::Environment::FilesHelper.find_files(path, rad.template.paths)
34
+ raise "multiple layout configs '#{layout}' for '#{theme}' theme!" if files.size > 1
35
+ if absolute_path = files.first
36
+ YAML.load_file(absolute_path).tap do |definition|
37
+ definition.must_be.a Hash
38
+ definition.must.include 'layout_template'
39
+ definition.must.include 'slots'
40
+ definition['slots'].must_be.a Hash
41
+ end
42
+ else
43
+ nil
44
+ end
45
+ end
46
+ cache_method_with_params_in_production :layout_definition
47
+ end
48
+ end
@@ -0,0 +1,74 @@
1
+ class Rad::Face::ThemedFormHelper
2
+ attr_accessor :template
3
+
4
+ def initialize template
5
+ self.template = template
6
+ end
7
+
8
+ def error_messages *errors
9
+ errors = errors.first if errors.size == 1 and errors.first.is_a? Array
10
+ template.render template.themed_partial('/forms/errors'), object: errors
11
+ end
12
+
13
+ def form_field options, &block
14
+ html_options = options.to_openobject
15
+ options = Rad::Face::HtmlOpenObject.new
16
+
17
+ # prepare options
18
+ %w(errors label description required theme).each do |k|
19
+ v = html_options.delete k
20
+ options[k] = v unless v.nil?
21
+ end
22
+ options.errors = options.errors.to_a
23
+
24
+ # CSS style
25
+ html_options.class ||= ""
26
+ html_options << " themed_input"
27
+
28
+ options.content = template.capture{block.call(html_options)}
29
+
30
+ html = template.render(template.themed_partial('/forms/field'), object: options)
31
+ template.concat html
32
+ end
33
+
34
+ def line *items
35
+ object = Rad::Face::HtmlOpenObject.initialize_from(items: items)
36
+ template.render template.themed_partial('/forms/line'), object: object
37
+ end
38
+
39
+ def self.generate_form_helper_methods methods
40
+ methods.each do |m|
41
+ define_method m do |*args|
42
+ options = args.extract_options!
43
+ template.capture do
44
+ form_field options do |html_options|
45
+ args << html_options
46
+ template.concat(template.send(m, *args))
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+
54
+ #
55
+ # Form fields
56
+ #
57
+ methods = %w(
58
+ check_box_tag
59
+ field_set_tag
60
+ file_field_tag
61
+ password_field_tag
62
+ radio_button_tag
63
+ select_tag
64
+ text_field_tag
65
+ text_area_tag
66
+ )
67
+ generate_form_helper_methods methods
68
+
69
+ %w(
70
+ hidden_field_tag
71
+ submit_tag
72
+ ).each{|m| delegate m, to: :template}
73
+
74
+ end
@@ -0,0 +1,96 @@
1
+ class Rad::Face::ViewBuilder
2
+
3
+ # def self.generate_view_helper_methods methods
4
+ # methods.each do |folder, templates|
5
+ # templates.each do |template|
6
+ # code = %{\
7
+ # def #{template} *args, &block
8
+ # render_block "#{folder}", "#{template}", *args, &block
9
+ # end}
10
+ #
11
+ # eval code, binding, __FILE__, __LINE__
12
+ # end
13
+ # end
14
+ # end
15
+
16
+ attr_reader :template
17
+ def initialize template
18
+ @template = template
19
+ end
20
+
21
+
22
+ #
23
+ # Template methods
24
+ #
25
+ %w(
26
+ capture
27
+ concat
28
+ content_for
29
+ tag
30
+ render
31
+ themed_partial
32
+ controller
33
+ ).each do |m|
34
+ delegate m, to: :template
35
+ end
36
+
37
+
38
+ #
39
+ # Builders
40
+ #
41
+ def options *args, &block
42
+ opt = args.extract_options!
43
+ args.size.must_be.in 0..1
44
+ opt[:content] = args.first if args.size == 1
45
+
46
+ Rad::Face::HamlBuilder.get_input self.template, opt, &block
47
+ end
48
+
49
+
50
+ #
51
+ # Forms
52
+ #
53
+ def form_tag *args, &block
54
+ f = Rad::Face::ThemedFormHelper.new(template)
55
+
56
+ content = block ? capture{block.call(f)} : ""
57
+ object = Rad::Face::HtmlOpenObject.initialize_from(form_attributes: args, content: content)
58
+ html = render(
59
+ themed_partial('/forms/form'),
60
+ object: object
61
+ )
62
+
63
+ if block
64
+ template.concat html
65
+ else
66
+ html
67
+ end
68
+ end
69
+
70
+ def form_for *args, &block
71
+ model_helper, options = template.build_form_model_helper_and_form_options *args
72
+
73
+ form_tag options do |themed_form_helper|
74
+ model_helper.form_helper = themed_form_helper
75
+
76
+ block.call model_helper if block
77
+ end
78
+ end
79
+
80
+ def render_block template, *args, &block
81
+ opt = options *args, &block
82
+ html = render themed_partial(template), object: opt
83
+ block ? self.concat(html) : html
84
+ end
85
+
86
+ def prepare_form! options, *args
87
+ buff = template.form_tag *args
88
+ options[:begin] = buff
89
+ options[:end] = '</form>'
90
+ end
91
+
92
+ protected
93
+ def method_missing m, *args, &block
94
+ render_block "/#{m}", *args, &block
95
+ end
96
+ end
@@ -0,0 +1,36 @@
1
+ module Rad::Face::ViewHelper
2
+ inject theme: :theme
3
+
4
+ def b
5
+ @b ||= Rad::Face::ViewBuilder.new self
6
+ end
7
+ alias_method :builder, :b
8
+
9
+ def unique_id
10
+ @unique_id ||= 0
11
+ @unique_id += 1
12
+ end
13
+
14
+ def themed_partial partial
15
+ partial.must =~ /^\//
16
+ themed_partial = "/#{rad.face.themes_path}/#{theme.name}#{partial}"
17
+ if rad.template.exist? themed_partial
18
+ themed_partial
19
+ else
20
+ "/#{rad.face.themes_path}/default#{partial}"
21
+ end
22
+ end
23
+
24
+ def build_layout layout = nil
25
+ # Configuring
26
+ theme.layout = layout
27
+
28
+ # Rendering
29
+ theme.layout_definition['slots'].each do |slot_name, slots|
30
+ slots = Array(slots)
31
+ slots.each do |partial|
32
+ content_for slot_name, render(partial)
33
+ end
34
+ end
35
+ end
36
+ end
data/readme.md ADDED
@@ -0,0 +1,3 @@
1
+ # Face (UI toolkit) for the Rad Framework
2
+
3
+ Tool for rapid interface creation, [add more]
@@ -0,0 +1,120 @@
1
+ require "spec_helper"
2
+
3
+ #
4
+ # Don't use should ==, it doesn't works with OpenObject
5
+ #
6
+ describe "HamlBuilder use cases" do
7
+ class TemplateStub
8
+ def self.capture &block
9
+ block.call
10
+ self.output
11
+ end
12
+
13
+ class << self
14
+ attr_accessor :output
15
+ end
16
+ end
17
+
18
+ def build *args, &block
19
+ opt = args.extract_options!
20
+ args.size.must_be.in 0..1
21
+ opt[:content] = args.first if args.size == 1
22
+
23
+ Rad::Face::HamlBuilder.get_input(TemplateStub, opt, &block)
24
+ end
25
+
26
+ it "should accept OpenObject as input" do
27
+ build({a: :b}.to_openobject).should == {a: :b}
28
+ end
29
+
30
+ it "hash" do
31
+ (build do |o|
32
+ o.a :b
33
+ end).should == {a: :b}
34
+
35
+ build(a: :b).should == {a: :b}
36
+ end
37
+
38
+ it "array" do
39
+ (build do |a|
40
+ a.add 1
41
+ a.add 2
42
+ end).should == {content: [1, 2]}
43
+
44
+ (build do |o|
45
+ o.a :b
46
+ o.ar do |a|
47
+ a.add 1
48
+ a.add 2
49
+ end
50
+ end).should == {a: :b, ar: [1, 2]}
51
+ end
52
+
53
+ it "capture" do
54
+ build("value").should == {content: "value"}
55
+
56
+ (build do
57
+ TemplateStub.output = "value"
58
+ end).should == {content: "value"}
59
+
60
+ (build do |o|
61
+ o.content do
62
+ TemplateStub.output = "value"
63
+ end
64
+ end).should == {content: "value"}
65
+
66
+ (build do |o|
67
+ o.value do
68
+ TemplateStub.output = "value"
69
+ end
70
+ end).should == {value: "value"}
71
+ end
72
+
73
+ it "invalid usage" do
74
+ -> {
75
+ build "value" do
76
+ TemplateStub.output = "value"
77
+ end
78
+ }.should raise_error(/Invalid usage!/)
79
+ end
80
+
81
+ it "merge" do
82
+ (build a: :b do
83
+ TemplateStub.output = "value"
84
+ end).should == {a: :b, content: "value"}
85
+
86
+ (build a: :b do |o|
87
+ o.c :d
88
+ end).should == {a: :b, c: :d}
89
+ end
90
+
91
+ it "nested" do
92
+ (build a: :b do |o|
93
+ o.a do |o|
94
+ o.b :c
95
+ end
96
+ end).should == {
97
+ a: {b: :c}
98
+ }
99
+ end
100
+
101
+ it "complex" do
102
+ (build a: :b do |o|
103
+ o.hs do |h|
104
+ h.c :d
105
+ end
106
+ o.ar do |a|
107
+ a.add 1
108
+ a.add 2
109
+ end
110
+ o.html do
111
+ TemplateStub.output = "value"
112
+ end
113
+ end).should == {
114
+ a: :b,
115
+ hs: {c: :d},
116
+ ar: [1, 2],
117
+ html: 'value'
118
+ }
119
+ end
120
+ end
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+
3
+ describe "HamlBuilder use cases" do
4
+ def build_hoo h
5
+ Rad::Face::HtmlOpenObject.initialize_from h
6
+ end
7
+
8
+ it "should threat newlines as blank" do
9
+ o = build_hoo(blank_line: "\n\n \t", line_with_content: "abc")
10
+ o.blank_line?.should be_false
11
+ o.line_with_content?.should be_true
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ require 'rspec_ext'
2
+
3
+ require 'rad_ext'
4
+ require 'rad/spec'
5
+
6
+ rad.face
@@ -0,0 +1,5 @@
1
+ <% if object.content? %>
2
+ content present
3
+ <% else %>
4
+ content blank
5
+ <% end %>
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Template" do
4
+ with_view_path spec_dir
5
+
6
+ inject template: :template
7
+
8
+ before do
9
+ @view_builder = Rad::Face::ViewBuilder.new rad.template
10
+ @view_builder.stub!(:themed_partial){|partial| partial}
11
+ end
12
+
13
+ it "should threat string with newlines as a blank string" do
14
+ @view_builder.render_block('/blank_symbols', content: "\n").should =~ /content blank/
15
+ end
16
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rad_face
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Alexey Petrushin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-07-04 00:00:00.000000000 +04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rad_core
17
+ requirement: &2956520 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *2956520
26
+ - !ruby/object:Gem::Dependency
27
+ name: rad_ext
28
+ requirement: &2956210 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *2956210
37
+ - !ruby/object:Gem::Dependency
38
+ name: rad_js
39
+ requirement: &2955920 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ type: :runtime
46
+ prerelease: false
47
+ version_requirements: *2955920
48
+ - !ruby/object:Gem::Dependency
49
+ name: rad_assets
50
+ requirement: &2955680 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ type: :runtime
57
+ prerelease: false
58
+ version_requirements: *2955680
59
+ description:
60
+ email:
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - Rakefile
66
+ - readme.md
67
+ - lib/components/face.rb
68
+ - lib/components/face.yml
69
+ - lib/components/theme.rb
70
+ - lib/face/face.rb
71
+ - lib/face/gems.rb
72
+ - lib/face/haml_builder.rb
73
+ - lib/face/html_open_object.rb
74
+ - lib/face/require.rb
75
+ - lib/face/support.rb
76
+ - lib/face/theme.rb
77
+ - lib/face/themed_form_helper.rb
78
+ - lib/face/view_builder.rb
79
+ - lib/face/view_helper.rb
80
+ - spec/haml_builder_spec.rb
81
+ - spec/html_open_object_spec.rb
82
+ - spec/spec_helper.rb
83
+ - spec/view_builder_spec/blank_symbols.html.erb
84
+ - spec/view_builder_spec.rb
85
+ has_rdoc: true
86
+ homepage: http://github.com/alexeypetrushin/rad_face
87
+ licenses: []
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 1.5.1
107
+ signing_key:
108
+ specification_version: 3
109
+ summary: User Interface tools for Rad Framework
110
+ test_files: []