hobo 1.0.3 → 1.1.0.pre0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +0 -66
- data/README +3 -0
- data/Rakefile +7 -7
- data/doctest/model.rdoctest +0 -2
- data/doctest/multi_model_forms.rdoctest +0 -2
- data/doctest/scopes.rdoctest +13 -21
- data/lib/active_record/association_collection.rb +7 -16
- data/lib/hobo.rb +10 -65
- data/lib/hobo/accessible_associations.rb +1 -5
- data/lib/hobo/authentication_support.rb +1 -1
- data/lib/hobo/controller.rb +5 -5
- data/lib/hobo/hobo_helper.rb +0 -84
- data/lib/hobo/lifecycles/lifecycle.rb +37 -31
- data/lib/hobo/lifecycles/transition.rb +1 -2
- data/lib/hobo/model.rb +13 -21
- data/lib/hobo/model_controller.rb +8 -8
- data/lib/hobo/rapid_helper.rb +12 -1
- data/lib/hobo/scopes/automatic_scopes.rb +26 -13
- data/lib/hobo/scopes/named_scope_extensions.rb +16 -28
- data/lib/hobo/user_controller.rb +1 -0
- data/lib/hobo/view_hints.rb +1 -5
- data/rails_generators/hobo/templates/initializer.rb +1 -1
- data/rails_generators/hobo_front_controller/templates/summary.dryml +4 -2
- data/rails_generators/hobo_model/hobo_model_generator.rb +12 -0
- data/rails_generators/hobo_model/templates/model.rb +9 -2
- data/rails_generators/hobo_rapid/templates/hobo-rapid.js +98 -23
- data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/clean.css +1 -1
- data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +3 -1
- data/{dryml_generators → rapid_generators}/rapid/cards.dryml.erb +0 -0
- data/{dryml_generators → rapid_generators}/rapid/forms.dryml.erb +0 -0
- data/{dryml_generators → rapid_generators}/rapid/pages.dryml.erb +1 -1
- data/taglibs/rapid.dryml +2 -0
- data/taglibs/rapid_core.dryml +10 -9
- data/taglibs/rapid_forms.dryml +70 -35
- data/taglibs/rapid_lifecycles.dryml +17 -4
- data/taglibs/rapid_plus.dryml +3 -3
- data/taglibs/rapid_summary.dryml +11 -0
- data/taglibs/rapid_user_pages.dryml +39 -28
- data/tasks/hobo_tasks.rake +1 -1
- metadata +45 -61
- data/hobo.gemspec +0 -226
- data/lib/hobo/dryml.rb +0 -188
- data/lib/hobo/dryml/dryml_builder.rb +0 -140
- data/lib/hobo/dryml/dryml_doc.rb +0 -159
- data/lib/hobo/dryml/dryml_generator.rb +0 -263
- data/lib/hobo/dryml/dryml_support_controller.rb +0 -13
- data/lib/hobo/dryml/parser.rb +0 -3
- data/lib/hobo/dryml/parser/attribute.rb +0 -41
- data/lib/hobo/dryml/parser/base_parser.rb +0 -254
- data/lib/hobo/dryml/parser/document.rb +0 -57
- data/lib/hobo/dryml/parser/element.rb +0 -27
- data/lib/hobo/dryml/parser/elements.rb +0 -45
- data/lib/hobo/dryml/parser/source.rb +0 -58
- data/lib/hobo/dryml/parser/text.rb +0 -13
- data/lib/hobo/dryml/parser/tree_parser.rb +0 -67
- data/lib/hobo/dryml/part_context.rb +0 -137
- data/lib/hobo/dryml/scoped_variables.rb +0 -42
- data/lib/hobo/dryml/tag_parameters.rb +0 -36
- data/lib/hobo/dryml/taglib.rb +0 -123
- data/lib/hobo/dryml/template.rb +0 -1019
- data/lib/hobo/dryml/template_environment.rb +0 -613
- data/lib/hobo/dryml/template_handler.rb +0 -187
- data/lib/hobo/static_tags +0 -98
- data/taglibs/core.dryml +0 -104
@@ -1,57 +0,0 @@
|
|
1
|
-
module Hobo::Dryml
|
2
|
-
|
3
|
-
module Parser
|
4
|
-
|
5
|
-
class Document < REXML::Document
|
6
|
-
|
7
|
-
def initialize(source, path)
|
8
|
-
super(nil)
|
9
|
-
|
10
|
-
# Replace <%...%> scriptlets with xml-safe references into a hash of scriptlets
|
11
|
-
@scriptlets = {}
|
12
|
-
source = source.gsub(/<%(.*?)%>/m) do
|
13
|
-
_, scriptlet = *Regexp.last_match
|
14
|
-
id = @scriptlets.size + 1
|
15
|
-
@scriptlets[id] = scriptlet
|
16
|
-
newlines = "\n" * scriptlet.count("\n")
|
17
|
-
"[![DRYML-ERB#{id}#{newlines}]!]"
|
18
|
-
end
|
19
|
-
|
20
|
-
|
21
|
-
@reference_src = "<dryml_page>" + source + "</dryml_page>"
|
22
|
-
rex_src = Hobo::Dryml::Parser::Source.new(@reference_src)
|
23
|
-
|
24
|
-
@elements = Hobo::Dryml::Parser::Elements.new(self)
|
25
|
-
build(rex_src)
|
26
|
-
|
27
|
-
rescue REXML::ParseException => e
|
28
|
-
raise Hobo::Dryml::DrymlSyntaxError, "File: #{path}\n#{e}"
|
29
|
-
end
|
30
|
-
|
31
|
-
|
32
|
-
def element_line_num(el)
|
33
|
-
offset = el.source_offset
|
34
|
-
@reference_src[0..offset].count("\n") + 1
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
def default_attribute_value
|
39
|
-
"&true"
|
40
|
-
end
|
41
|
-
|
42
|
-
|
43
|
-
def restore_erb_scriptlets(src)
|
44
|
-
src.gsub(/\[!\[DRYML-ERB(\d+)\s*\]!\]/m) {|s| "<%#{@scriptlets[$1.to_i]}%>" }
|
45
|
-
end
|
46
|
-
|
47
|
-
|
48
|
-
private
|
49
|
-
def build( source )
|
50
|
-
Hobo::Dryml::Parser::TreeParser.new( source, self ).parse
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
module Hobo::Dryml::Parser
|
2
|
-
|
3
|
-
class Element < REXML::Element
|
4
|
-
|
5
|
-
def initialize(*args)
|
6
|
-
super
|
7
|
-
@elements = Hobo::Dryml::Parser::Elements.new(self)
|
8
|
-
end
|
9
|
-
|
10
|
-
def dryml_name
|
11
|
-
expanded_name.sub(/:.*/, "")
|
12
|
-
end
|
13
|
-
|
14
|
-
attr_accessor :start_tag_source, :source_offset
|
15
|
-
|
16
|
-
attr_writer :has_end_tag
|
17
|
-
def has_end_tag?
|
18
|
-
@has_end_tag
|
19
|
-
end
|
20
|
-
|
21
|
-
def parameter_tag?
|
22
|
-
expanded_name =~ /:$/
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
module Hobo::Dryml::Parser
|
2
|
-
|
3
|
-
class Element < REXML::Element
|
4
|
-
|
5
|
-
def initialize(*args)
|
6
|
-
super
|
7
|
-
@elements = Hobo::Dryml::Parser::Elements.new(self)
|
8
|
-
end
|
9
|
-
|
10
|
-
def dryml_name
|
11
|
-
expanded_name.sub(/:.*/, "")
|
12
|
-
end
|
13
|
-
|
14
|
-
attr_accessor :start_tag_source, :source_offset
|
15
|
-
|
16
|
-
attr_writer :has_end_tag
|
17
|
-
def has_end_tag?
|
18
|
-
@has_end_tag
|
19
|
-
end
|
20
|
-
|
21
|
-
def parameter_tag?
|
22
|
-
expanded_name =~ /:$/
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
26
|
-
|
27
|
-
class Elements < REXML::Elements
|
28
|
-
|
29
|
-
# Override to ensure DRYML elements are created
|
30
|
-
def add(element=nil)
|
31
|
-
rv = nil
|
32
|
-
if element.nil?
|
33
|
-
Hobo::Dryml::Parser::Element.new("", self, @element.context)
|
34
|
-
elsif not element.kind_of?(Element)
|
35
|
-
Hobo::Dryml::Parser::Element.new(element, self, @element.context)
|
36
|
-
else
|
37
|
-
@element << element
|
38
|
-
element.context = @element.context
|
39
|
-
element
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
@@ -1,58 +0,0 @@
|
|
1
|
-
module Hobo::Dryml::Parser
|
2
|
-
|
3
|
-
# A REXML source that keeps track of where in the buffer it is
|
4
|
-
class Source < REXML::Source
|
5
|
-
|
6
|
-
def initialize(src)
|
7
|
-
super(src)
|
8
|
-
@buffer_offset = 0
|
9
|
-
end
|
10
|
-
|
11
|
-
attr_reader :last_match_offset
|
12
|
-
|
13
|
-
def remember_match(m)
|
14
|
-
if m
|
15
|
-
@last_match = m
|
16
|
-
@last_match_offset = @buffer_offset + m.begin(0)
|
17
|
-
@orig[@last_match_offset..@last_match_offset+m[0].length] == @buffer[m.begin(0)..m.end(0)]
|
18
|
-
end
|
19
|
-
m
|
20
|
-
end
|
21
|
-
|
22
|
-
def advance_buffer(md)
|
23
|
-
@buffer = md.post_match
|
24
|
-
@buffer_offset += md.end(0)
|
25
|
-
end
|
26
|
-
|
27
|
-
def scan(pattern, cons=false)
|
28
|
-
raise '!'
|
29
|
-
return nil if @buffer.nil?
|
30
|
-
rv = @buffer.scan(pattern)
|
31
|
-
if cons and rv.size > 0
|
32
|
-
advance_buffer(Regexp.last_match)
|
33
|
-
end
|
34
|
-
rv
|
35
|
-
end
|
36
|
-
|
37
|
-
def consume(pattern)
|
38
|
-
md = remember_match(pattern.match(@buffer))
|
39
|
-
if md
|
40
|
-
advance_buffer(md)
|
41
|
-
@buffer
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def match(pattern, cons=false)
|
46
|
-
md = remember_match(pattern.match(@buffer))
|
47
|
-
advance_buffer(md) if cons and md
|
48
|
-
return md
|
49
|
-
end
|
50
|
-
|
51
|
-
def current_line
|
52
|
-
pos = last_match_offset || 0
|
53
|
-
[0, 0, @orig[0..pos].count("\n") + 1]
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
module Hobo::Dryml::Parser
|
2
|
-
|
3
|
-
class Text < REXML::Text
|
4
|
-
|
5
|
-
def parent=(parent)
|
6
|
-
# Bypass immediate super
|
7
|
-
REXML::Child.instance_method(:parent=).bind(self).call(parent)
|
8
|
-
Text.check(@string, /</, nil) if @raw and @parent && Text.respond_to?(:check)
|
9
|
-
end
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
module Hobo::Dryml::Parser
|
2
|
-
|
3
|
-
class TreeParser < REXML::Parsers::TreeParser
|
4
|
-
def initialize( source, build_context = Document.new )
|
5
|
-
@build_context = build_context
|
6
|
-
@parser = Hobo::Dryml::Parser::BaseParser.new(source)
|
7
|
-
end
|
8
|
-
|
9
|
-
|
10
|
-
def parse
|
11
|
-
tag_stack = []
|
12
|
-
in_doctype = false
|
13
|
-
entities = nil
|
14
|
-
begin
|
15
|
-
while true
|
16
|
-
event = @parser.pull
|
17
|
-
#STDERR.puts "TREEPARSER GOT #{event.inspect}"
|
18
|
-
case event[0]
|
19
|
-
when :end_document
|
20
|
-
unless tag_stack.empty?
|
21
|
-
#raise ParseException.new("No close tag for #{tag_stack.inspect}")
|
22
|
-
raise ParseException.new("No close tag for #{@build_context.xpath}")
|
23
|
-
end
|
24
|
-
return
|
25
|
-
when :start_element
|
26
|
-
tag_stack.push(event[1])
|
27
|
-
el = @build_context = @build_context.add_element( event[1] )
|
28
|
-
event[2].each do |key, value|
|
29
|
-
el.attributes[key]=Hobo::Dryml::Parser::Attribute.new(key,value,self)
|
30
|
-
end
|
31
|
-
@build_context.start_tag_source = event[3]
|
32
|
-
@build_context.source_offset = event[4]
|
33
|
-
when :end_element
|
34
|
-
tag_stack.pop
|
35
|
-
@build_context.has_end_tag = event[2]
|
36
|
-
@build_context = @build_context.parent
|
37
|
-
when :text
|
38
|
-
if not in_doctype
|
39
|
-
if @build_context[-1].instance_of? Text
|
40
|
-
@build_context[-1] << event[1]
|
41
|
-
else
|
42
|
-
@build_context.add(
|
43
|
-
Hobo::Dryml::Parser::Text.new(event[1], @build_context.whitespace, nil, true)
|
44
|
-
) unless (
|
45
|
-
@build_context.ignore_whitespace_nodes and
|
46
|
-
event[1].strip.size==0
|
47
|
-
)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
when :comment
|
51
|
-
c = REXML::Comment.new( event[1] )
|
52
|
-
@build_context.add( c )
|
53
|
-
when :cdata
|
54
|
-
c = REXML::CData.new( event[1] )
|
55
|
-
@build_context.add( c )
|
56
|
-
when :processing_instruction
|
57
|
-
@build_context.add( Instruction.new( event[1], event[2] ) )
|
58
|
-
end
|
59
|
-
end
|
60
|
-
rescue REXML::Validation::ValidationException
|
61
|
-
raise
|
62
|
-
rescue
|
63
|
-
raise REXML::ParseException.new( $!.message, @parser.source, @parser, $! )
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
@@ -1,137 +0,0 @@
|
|
1
|
-
module Hobo
|
2
|
-
|
3
|
-
module Dryml
|
4
|
-
|
5
|
-
# Raised when the part context fails its integrity check.
|
6
|
-
class PartContext
|
7
|
-
|
8
|
-
class TamperedWithPartContext < StandardError; end
|
9
|
-
|
10
|
-
class TypedId < String; end
|
11
|
-
|
12
|
-
class << self
|
13
|
-
attr_accessor :secret, :digest
|
14
|
-
end
|
15
|
-
self.digest = 'SHA1'
|
16
|
-
|
17
|
-
|
18
|
-
def self.client_side_storage(contexts, session)
|
19
|
-
return "" if contexts.empty?
|
20
|
-
|
21
|
-
contexts.map do |dom_id, context|
|
22
|
-
code = context.marshal(session).split("\n").map{|line| "'#{line}\\n'"}.join(" +\n ")
|
23
|
-
"hoboParts['#{dom_id}'] = (#{code});\n"
|
24
|
-
end.join
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
|
-
def self.pre_marshal(x)
|
29
|
-
if x.is_a?(ActiveRecord::Base) && x.respond_to?(:typed_id)
|
30
|
-
TypedId.new(x.typed_id)
|
31
|
-
else
|
32
|
-
x
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
|
37
|
-
def self.for_call(part_name, environment, locals)
|
38
|
-
new do |c|
|
39
|
-
c.part_name = part_name
|
40
|
-
c.locals = locals.map { |l| pre_marshal(l) }
|
41
|
-
c.this_id = environment.typed_id
|
42
|
-
c.form_field_path = environment.form_field_path
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
|
47
|
-
def self.for_refresh(encoded_context, page_this, session)
|
48
|
-
new do |c|
|
49
|
-
c.unmarshal(encoded_context, page_this, session)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
|
54
|
-
def initialize
|
55
|
-
yield self
|
56
|
-
end
|
57
|
-
|
58
|
-
attr_accessor :part_name, :locals, :this, :this_field, :this_id, :form_field_path
|
59
|
-
|
60
|
-
|
61
|
-
def marshal(session)
|
62
|
-
context = [@part_name, @this_id, @locals]
|
63
|
-
context << form_field_path if form_field_path
|
64
|
-
data = Base64.encode64(Marshal.dump(context)).strip
|
65
|
-
digest = generate_digest(data, session)
|
66
|
-
"#{data}--#{digest}"
|
67
|
-
end
|
68
|
-
|
69
|
-
|
70
|
-
# Unmarshal part context to a hash and verify its integrity.
|
71
|
-
def unmarshal(client_store, page_this, session)
|
72
|
-
data, digest = CGI.unescape(client_store).strip.split('--')
|
73
|
-
|
74
|
-
raise TamperedWithPartContext unless digest == generate_digest(data, session)
|
75
|
-
|
76
|
-
context = Marshal.load(Base64.decode64(data))
|
77
|
-
|
78
|
-
part_name, this_id, locals, form_field_path = context
|
79
|
-
|
80
|
-
if RAILS_DEFAULT_LOGGER
|
81
|
-
RAILS_DEFAULT_LOGGER.info "Call part: #{part_name}. this-id = #{this_id}, locals = #{locals.inspect}"
|
82
|
-
RAILS_DEFAULT_LOGGER.info " : form_field_path = #{form_field_path.inspect}" if form_field_path
|
83
|
-
end
|
84
|
-
|
85
|
-
self.part_name = part_name
|
86
|
-
self.this_id = this_id
|
87
|
-
self.locals = restore_locals(locals)
|
88
|
-
self.form_field_path = form_field_path
|
89
|
-
|
90
|
-
parse_this_id(page_this)
|
91
|
-
end
|
92
|
-
|
93
|
-
|
94
|
-
# Generate the HMAC keyed message digest. Uses SHA1 by default.
|
95
|
-
def generate_digest(data, session)
|
96
|
-
secret = self.class.secret || ActionController::Base.session_options[:secret] || ActionController::Base.cached_session_options.first[:secret]
|
97
|
-
key = secret.respond_to?(:call) ? secret.call(session) : secret
|
98
|
-
OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new(self.class.digest), key, data)
|
99
|
-
end
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
def parse_this_id(page_this)
|
104
|
-
if this_id == "this"
|
105
|
-
self.this = page_this
|
106
|
-
elsif this_id =~ /^this:(.*)/
|
107
|
-
self.this = page_this
|
108
|
-
self.this_field = $1
|
109
|
-
elsif this_id == "nil"
|
110
|
-
nil
|
111
|
-
else
|
112
|
-
parts = this_id.split(':')
|
113
|
-
if parts.length == 3
|
114
|
-
self.this = Hobo::Model.find_by_typed_id("#{parts[0]}:#{parts[1]}")
|
115
|
-
self.this_field = parts[2]
|
116
|
-
else
|
117
|
-
self.this = Hobo::Model.find_by_typed_id(this_id)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
|
123
|
-
def restore_locals(locals)
|
124
|
-
locals.map do |l|
|
125
|
-
if l.is_a?(TypedId)
|
126
|
-
Hobo::Model.find_by_typed_id(l)
|
127
|
-
else
|
128
|
-
l
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
end
|
134
|
-
|
135
|
-
end
|
136
|
-
|
137
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
module Hobo::Dryml
|
2
|
-
|
3
|
-
class ScopedVariables
|
4
|
-
|
5
|
-
def initialize(variables=nil)
|
6
|
-
@scopes = variables ? [variables] : []
|
7
|
-
end
|
8
|
-
|
9
|
-
def [](key)
|
10
|
-
s = scope_with_key(key) and s[key]
|
11
|
-
end
|
12
|
-
|
13
|
-
def []=(key, val)
|
14
|
-
s = scope_with_key(key) or raise ArgumentError, "no such scoped variable: #{key}"
|
15
|
-
s[key] = val
|
16
|
-
end
|
17
|
-
|
18
|
-
def new_scope(variables)
|
19
|
-
@scopes << variables.dup
|
20
|
-
res = yield
|
21
|
-
@scopes.pop
|
22
|
-
res
|
23
|
-
end
|
24
|
-
|
25
|
-
def scope_with_key(key)
|
26
|
-
@scopes.reverse_each do |s|
|
27
|
-
return s if s.has_key?(key)
|
28
|
-
end
|
29
|
-
nil
|
30
|
-
end
|
31
|
-
|
32
|
-
def method_missing(name, *args)
|
33
|
-
if name.to_s =~ /=$/
|
34
|
-
self[name.to_s[0..-2].to_sym] = args.first
|
35
|
-
else
|
36
|
-
self[name]
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|