hobo 1.0.3 → 1.1.0.pre0
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/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
|