wrap_it 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rubocop.yml +5 -0
- data/Gemfile +7 -0
- data/README.md +277 -0
- data/Rakefile +14 -0
- data/config.ru +4 -0
- data/lib/wrap_it/arguments_array.rb +128 -0
- data/lib/wrap_it/base.rb +108 -0
- data/lib/wrap_it/callbacks.rb +63 -0
- data/lib/wrap_it/container.rb +84 -0
- data/lib/wrap_it/derived_attributes.rb +37 -0
- data/lib/wrap_it/enums.rb +89 -0
- data/lib/wrap_it/html_class.rb +193 -0
- data/lib/wrap_it/no_rails.rb +66 -0
- data/lib/wrap_it/rails.rb +51 -0
- data/lib/wrap_it/switches.rb +82 -0
- data/lib/wrap_it/text_container.rb +25 -0
- data/lib/wrap_it/version.rb +3 -0
- data/lib/wrap_it.rb +74 -0
- data/spec/internal/log/test.log +619 -0
- data/spec/lib/arguments_array_spec.rb +83 -0
- data/spec/lib/base_spec.rb +48 -0
- data/spec/lib/callbacks_spec.rb +5 -0
- data/spec/lib/container_spec.rb +9 -0
- data/spec/lib/derived_attributes_spec.rb +51 -0
- data/spec/lib/enums_spec.rb +79 -0
- data/spec/lib/html_class_spec.rb +98 -0
- data/spec/lib/switches_spec.rb +66 -0
- data/spec/rails/base_spec.rb +20 -0
- data/spec/rails/container_spec.rb +30 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/example_groups/rails_example_group.rb +79 -0
- data/spec/support/example_groups/wrap_it_example_group.rb +39 -0
- data/wrap_it.gemspec +30 -0
- metadata +179 -0
@@ -0,0 +1,84 @@
|
|
1
|
+
module WrapIt
|
2
|
+
#
|
3
|
+
# Describes elements that can contain other elements
|
4
|
+
#
|
5
|
+
# @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
|
6
|
+
#
|
7
|
+
class Container < Base
|
8
|
+
switch :deffered_render
|
9
|
+
|
10
|
+
after_initialize do
|
11
|
+
@children = deffered_render? ? [] : empty_html
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.child(*args, &block)
|
15
|
+
create_args = args.last.is_a?(Array) ? args.pop : []
|
16
|
+
klass = args.pop
|
17
|
+
klass.is_a?(Class) && klass = klass.name
|
18
|
+
unless klass.is_a?(String)
|
19
|
+
args.push(klass)
|
20
|
+
klass = 'WrapIt::Base'
|
21
|
+
end
|
22
|
+
args.select! { |n| n.is_a?(Symbol) }
|
23
|
+
args.size > 0 || fail(ArgumentError, 'No valid method names given')
|
24
|
+
args.each do |method|
|
25
|
+
define_method method do |*helper_args, &helper_block|
|
26
|
+
# We should clone arguments becouse if we have loop in template,
|
27
|
+
# `extract_options!` below works only for first iterration
|
28
|
+
default_args = create_args.clone
|
29
|
+
options = helper_args.extract_options!
|
30
|
+
options[:helper_name] = method
|
31
|
+
options.merge!(default_args.extract_options!)
|
32
|
+
helper_args += default_args + [options]
|
33
|
+
add_children(klass, block, *helper_args, &helper_block)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# protected
|
39
|
+
|
40
|
+
after_capture do
|
41
|
+
if deffered_render?
|
42
|
+
html = Hash[@children.map { |c| [c.object_id, capture { c.render }] }]
|
43
|
+
if omit_content?
|
44
|
+
@content = html.values.reduce(empty_html) { |a, e| a << e }
|
45
|
+
else
|
46
|
+
safe = html_safe?(@content)
|
47
|
+
@content = @content
|
48
|
+
.split(CONTENT_SPLIT_REGEXP)
|
49
|
+
.reduce(empty_html) do |a, e|
|
50
|
+
match = CONTENT_REPLACE_REGEXP.match(e)
|
51
|
+
safe || e = html_safe(e)
|
52
|
+
a << match.nil? ? e : html[match[:obj_id].to_i(16)]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
else
|
56
|
+
omit_content? && @content = @children
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
CONTENT_SPLIT_REGEXP = /(<!-- WrapIt::Container\(\h+\) -->)/
|
63
|
+
CONTENT_REPLACE_REGEXP = /\A<!-- WrapIt::Container\((?<obj_id>\h+)\) -->\z/
|
64
|
+
|
65
|
+
def add_children(helper_class, class_block, *args, &helper_block)
|
66
|
+
item = Object
|
67
|
+
.const_get(helper_class)
|
68
|
+
.new(@template, *args, &helper_block)
|
69
|
+
class_block.nil? || instance_exec(item, &class_block)
|
70
|
+
|
71
|
+
item = item.render unless deffered_render?
|
72
|
+
@children << item if deffered_render? || omit_content?
|
73
|
+
if omit_content?
|
74
|
+
empty_html
|
75
|
+
else
|
76
|
+
if deffered_render?
|
77
|
+
html_safe("<!-- WrapIt::Container(#{item.object_id.to_s(16)}) -->")
|
78
|
+
else
|
79
|
+
item
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module WrapIt
|
2
|
+
#
|
3
|
+
# Adds minimal support to retrieve derived class variables
|
4
|
+
#
|
5
|
+
# @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
|
6
|
+
#
|
7
|
+
module DerivedAttributes
|
8
|
+
def self.included(base)
|
9
|
+
base.extend ClassMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
#
|
13
|
+
# Class methods to include
|
14
|
+
#
|
15
|
+
module ClassMethods
|
16
|
+
def get_derived(name)
|
17
|
+
return instance_variable_get(name) if instance_variable_defined?(name)
|
18
|
+
ancestors.each do |ancestor|
|
19
|
+
break if ancestor == Base
|
20
|
+
next unless ancestor.instance_variable_defined?(name)
|
21
|
+
return ancestor.instance_variable_get(name)
|
22
|
+
end
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def collect_derived(name, initial = [], method = :concat)
|
27
|
+
result = initial
|
28
|
+
ancestors.each do |ancestor|
|
29
|
+
break if ancestor == Base
|
30
|
+
next unless ancestor.instance_variable_defined?(name)
|
31
|
+
result = result.send(method, ancestor.instance_variable_get(name))
|
32
|
+
end
|
33
|
+
result
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module WrapIt
|
2
|
+
#
|
3
|
+
# Adds enums functionality
|
4
|
+
#
|
5
|
+
# @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
|
6
|
+
#
|
7
|
+
module Enums
|
8
|
+
def self.included(base)
|
9
|
+
base <= Base || fail(
|
10
|
+
TypeError,
|
11
|
+
"#{self.class.name} can be included only into WrapIt::Base subclasses"
|
12
|
+
)
|
13
|
+
extend DerivedAttributes
|
14
|
+
base.extend ClassMethods
|
15
|
+
base.after_initialize :enums_init
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def enums_init
|
21
|
+
opt_keys = @options.keys
|
22
|
+
self.class.collect_derived(:@enums, {}, :merge).each do |name, opts|
|
23
|
+
value = nil
|
24
|
+
names = [name] + [opts[:aliases] || []].flatten
|
25
|
+
opt_keys.select { |o| names.include? o }.each do |key|
|
26
|
+
tmp = @options.delete(key)
|
27
|
+
value ||= tmp
|
28
|
+
!value.nil? && !opts[:values].include?(value) && value = nil
|
29
|
+
end
|
30
|
+
@arguments.extract!(Symbol, and: [opts[:values]]).each do |key|
|
31
|
+
value ||= key
|
32
|
+
end
|
33
|
+
send("#{name}=", value)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# Class methods to include
|
39
|
+
#
|
40
|
+
module ClassMethods
|
41
|
+
#
|
42
|
+
# @dsl
|
43
|
+
# Adds `enum`. When element created, creation arguments will be scanned
|
44
|
+
# for `Symbol`, that included contains in `values`. If it founded, enum
|
45
|
+
# takes this value. Also creation options inspected. If its contains
|
46
|
+
# `name: value` key-value pair with valid value, this pair removed from
|
47
|
+
# options and enum takes this value.
|
48
|
+
#
|
49
|
+
# This method also adds getter and setter for this enum.
|
50
|
+
#
|
51
|
+
# @param name [String, Symbol] Enum name. Converted to `Symbol`.
|
52
|
+
# @param options = {} [Hash] Enum options
|
53
|
+
# @options options [String, Symbol] :html_class_prefix prefix of HTML
|
54
|
+
# class that will automatically added to element if enum changes its
|
55
|
+
# value.
|
56
|
+
# @options options [Symbol, Array<Symbol>] :aliases list of enum aliases.
|
57
|
+
# Warning! Values are not converted - pass only `Symbols` here.
|
58
|
+
# @options options [String, Symbol] :default default value for enum,
|
59
|
+
# if nil or wrong value given. Converted to `Symbol`.
|
60
|
+
# @yield [value] Runs block when enum value changed, gives it to block.
|
61
|
+
# @yieldparam value [Symbol] New enum value.
|
62
|
+
# @yieldreturn [void]
|
63
|
+
#
|
64
|
+
# @return [void]
|
65
|
+
def enum(name, values, options = {}, &block)
|
66
|
+
options.symbolize_keys!
|
67
|
+
name = name.to_sym
|
68
|
+
options.merge!(block: block, name: name, values: values)
|
69
|
+
options.key?(:default) && options[:default] = options[:default].to_sym
|
70
|
+
options.key?(:html_class_prefix) && options[:regexp] =
|
71
|
+
/\A#{options[:html_class_prefix]}(?:#{values.join('|')})\z/
|
72
|
+
var = "@#{name}".to_sym
|
73
|
+
define_method("#{name}") { instance_variable_get(var) }
|
74
|
+
define_method("#{name}=") do |value|
|
75
|
+
v = value if values.include?(value)
|
76
|
+
v ||= options[:default] if options.key?(:default)
|
77
|
+
instance_variable_set(var, v)
|
78
|
+
block.nil? || instance_exec(v, &block)
|
79
|
+
if options.key?(:regexp)
|
80
|
+
remove_html_class(options[:regexp])
|
81
|
+
v.nil? || add_html_class("#{options[:html_class_prefix]}#{v}")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
@enums ||= {}
|
85
|
+
@enums[name] = options
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
module WrapIt
|
2
|
+
#
|
3
|
+
# Methods for manipulationg with HTML class. For internal usage.
|
4
|
+
# You should not include this class directly - subclass from
|
5
|
+
# `WrapIt::Base` instead.
|
6
|
+
#
|
7
|
+
# @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
|
8
|
+
#
|
9
|
+
module HTMLClass
|
10
|
+
extend DerivedAttributes
|
11
|
+
|
12
|
+
def self.included(base)
|
13
|
+
base <= Base || fail(
|
14
|
+
TypeError,
|
15
|
+
"#{self.class.name} can be included only into WrapIt::Base subclasses"
|
16
|
+
)
|
17
|
+
base.extend ClassMethods
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# html class getter
|
22
|
+
#
|
23
|
+
# @return [Array<String>] array of html classes of element
|
24
|
+
def html_class
|
25
|
+
@options[:class]
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Sets html class(es) for element
|
30
|
+
# @param value [Symbol, String, Array<Symbol, String>] HTML class or list
|
31
|
+
# of classes. All classes will be converted to Strings, duplicates are
|
32
|
+
# removed.
|
33
|
+
# @return [void]
|
34
|
+
#
|
35
|
+
# @example
|
36
|
+
# element.html_class = [:a, 'b', ['c', :d, 'a']]
|
37
|
+
# element.html_class #=> ['a', 'b', 'c', 'd']
|
38
|
+
def html_class=(value)
|
39
|
+
@options[:class] = []
|
40
|
+
add_html_class(value)
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Adds html class(es) to element. Chaining allowed. All classes will be
|
45
|
+
# converted to Strings, duplicates are removed.
|
46
|
+
# @override add_html_class([[html_class], ...])
|
47
|
+
# @param html_class [Symbol, String, Array<Symbol, String>]
|
48
|
+
# HTML class or list of HTML classes.
|
49
|
+
# @return [self]
|
50
|
+
#
|
51
|
+
# @example
|
52
|
+
# element.html_class = 'a'
|
53
|
+
# element.add_html_class :b, :c, ['d', :c, :e, 'a']
|
54
|
+
# element.html_class #=> ['a', 'b', 'c', 'd', 'e']
|
55
|
+
def add_html_class(*args)
|
56
|
+
@options[:class] += args.flatten.map { |c| c.to_s }
|
57
|
+
@options[:class].uniq!
|
58
|
+
self # allow chaining
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Removes html class(es) from element. Chaining allowed
|
63
|
+
# @override add_html_class([[html_class], ...])
|
64
|
+
# @param html_class [Symbol, String, Regexp, Array<Symbol, String, Regexp>]
|
65
|
+
# HTML class or list of HTML classes.
|
66
|
+
# @return [self]
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
# element.add_html_class %w(a b c d e)
|
70
|
+
# element.remove_html_class :b, ['c', :e]
|
71
|
+
# element.html_class #=> ['a', 'd']
|
72
|
+
def remove_html_class(*args)
|
73
|
+
args.flatten!
|
74
|
+
re = []
|
75
|
+
args.reject! { |c| c.is_a?(Regexp) && re << c && true }
|
76
|
+
args = args.uniq.map { |c| c.to_s }
|
77
|
+
args.size > 0 && @options[:class].reject! { |c| args.include?(c) }
|
78
|
+
re.is_a?(Array) && re.each do |r|
|
79
|
+
@options[:class].reject! { |c| r.match(c) }
|
80
|
+
end
|
81
|
+
self # allow chaining
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# Determines whether element contains class, satisfied by conditions,
|
86
|
+
# specified in method arguments.
|
87
|
+
#
|
88
|
+
# There are two forms of method call: with list of conditions as arguments
|
89
|
+
# and with block for comparing. Method makes comparison with html class
|
90
|
+
# untill first `true` return value or end of list. All conditions should
|
91
|
+
# be satisfied for `true` return of this method.
|
92
|
+
#
|
93
|
+
# In first form, each argument treated as condition. Condition can be a
|
94
|
+
# `Regexp`, so html classes of element tested for matching to that
|
95
|
+
# regular expression. If condition is an `Array` then every class will be
|
96
|
+
# tested for presence in this array. If condition is `Symbol` or `String`
|
97
|
+
# classes will be compared with it via equality operator `==`.
|
98
|
+
#
|
99
|
+
# In second form all arguments are ignored and for each comparison given
|
100
|
+
# block called with html class as argument. Block return value then used.
|
101
|
+
#
|
102
|
+
# @overload html_class([condition, ...])
|
103
|
+
# @param condition [<Regexp, Symbol, String, Array<String>]
|
104
|
+
# condition for comparison.
|
105
|
+
#
|
106
|
+
# @overload html_class(&block)
|
107
|
+
# @yield [html_class] Gives each html class to block. You should return
|
108
|
+
# `true` if element contains this html class.
|
109
|
+
# @yieldparam html_class [String] html class to inspect.
|
110
|
+
# @yieldreturn [Boolean] whether element has html class.
|
111
|
+
#
|
112
|
+
# @return [Boolean] whether element has class with specified conditions.
|
113
|
+
#
|
114
|
+
# @example with `Symbol` or `String` conditions
|
115
|
+
# element.html_class = [:a, :b, :c]
|
116
|
+
# element.html_class?(:a) #=> true
|
117
|
+
# element.html_class?(:d) #=> false
|
118
|
+
# element.html_class?(:a, 'b') #=> true
|
119
|
+
# element.html_class?(:a, :d) #=> false
|
120
|
+
#
|
121
|
+
# @example with `Regexp` conditions
|
122
|
+
# element.html_class = [:some, :test]
|
123
|
+
# element.html_class?(/some/) #=> true
|
124
|
+
# element.html_class?(/some/, /bad/) #=> false
|
125
|
+
# element.html_class?(/some/, :test) #=> true
|
126
|
+
#
|
127
|
+
# @example with `Array` conditions
|
128
|
+
# element.html_class = [:a, :b, :c]
|
129
|
+
# element.html_class?(%w(a d)) #=> true
|
130
|
+
# element.html_class?(%w(e d)) #=> false
|
131
|
+
#
|
132
|
+
# @example with block
|
133
|
+
# element.html_class = [:a, :b, :c]
|
134
|
+
# element.html_class? { |x| x == 'a' } #=> true
|
135
|
+
def html_class?(*args, &block)
|
136
|
+
args.all? { |c| inspect_class(:any?, c, &block) }
|
137
|
+
end
|
138
|
+
|
139
|
+
#
|
140
|
+
# Determines whether element doesn't contains class, satisfied by
|
141
|
+
# conditions, specified in method arguments.
|
142
|
+
#
|
143
|
+
# @see html_class?
|
144
|
+
def no_html_class?(*args, &block)
|
145
|
+
args.all? { |c| inspect_class(:none?, c, &block) }
|
146
|
+
end
|
147
|
+
|
148
|
+
protected
|
149
|
+
|
150
|
+
def add_default_classes
|
151
|
+
add_html_class self.class.collect_derived(:@html_class)
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
def inspect_class(with, value = nil, &block)
|
157
|
+
if block_given?
|
158
|
+
@options[:class].send(with, &block)
|
159
|
+
else
|
160
|
+
case
|
161
|
+
when value.is_a?(Regexp)
|
162
|
+
@options[:class].send(with) { |c| value.match(c) }
|
163
|
+
when value.is_a?(String) || value.is_a?(Symbol)
|
164
|
+
@options[:class].send(with) { |c| value.to_s == c }
|
165
|
+
when value.is_a?(Array)
|
166
|
+
@options[:class].send(with) { |c| value.include?(c) }
|
167
|
+
else
|
168
|
+
false
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
#
|
174
|
+
# Class methods to include
|
175
|
+
#
|
176
|
+
module ClassMethods
|
177
|
+
#
|
178
|
+
# @dsl
|
179
|
+
# Adds default html classes, thats are automatically added when element
|
180
|
+
# created.
|
181
|
+
# @override html_class([html_class, ...])
|
182
|
+
# @param html_class [String, Symbol, Array<String, Symbol>] HTML class.
|
183
|
+
# Converted to `String`
|
184
|
+
#
|
185
|
+
# @return [void]
|
186
|
+
def html_class(*args)
|
187
|
+
@html_class ||= []
|
188
|
+
@html_class += args.flatten.map { |c| c.to_s }
|
189
|
+
@html_class.uniq!
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
|
2
|
+
methods = Hash.public_instance_methods(true)
|
3
|
+
unless methods.include?(:extractable_options?)
|
4
|
+
Hash.send(:define_method, :extractable_options?, proc do
|
5
|
+
instance_of?(Hash)
|
6
|
+
end)
|
7
|
+
end
|
8
|
+
|
9
|
+
unless methods.include?(:symbolize_keys!)
|
10
|
+
Hash.send(:define_method, :symbolize_keys!, proc do
|
11
|
+
keys.each do |key|
|
12
|
+
next unless key.respond_to?(:to_sym)
|
13
|
+
self[key.to_sym] = delete(key)
|
14
|
+
end
|
15
|
+
self
|
16
|
+
end)
|
17
|
+
end
|
18
|
+
|
19
|
+
methods = Array.public_instance_methods(true)
|
20
|
+
unless methods.include?(:extract_options!)
|
21
|
+
Array.send(:define_method, :extract_options!, proc do
|
22
|
+
if last.is_a?(Hash) && last.extractable_options?
|
23
|
+
pop
|
24
|
+
else
|
25
|
+
{}
|
26
|
+
end
|
27
|
+
end)
|
28
|
+
end
|
29
|
+
|
30
|
+
module WrapIt
|
31
|
+
#
|
32
|
+
# Non rails render implementation
|
33
|
+
#
|
34
|
+
module Renderer
|
35
|
+
def empty_html
|
36
|
+
''
|
37
|
+
end
|
38
|
+
|
39
|
+
def capture(text = nil)
|
40
|
+
block_given? ? yield : text
|
41
|
+
end
|
42
|
+
|
43
|
+
def concat(text)
|
44
|
+
@buffer ||= empty_html
|
45
|
+
@buffer << text
|
46
|
+
end
|
47
|
+
|
48
|
+
def output_buffer
|
49
|
+
@buffer
|
50
|
+
end
|
51
|
+
|
52
|
+
def content_tag(tag, body, options = {})
|
53
|
+
arr = [tag]
|
54
|
+
options.each { |o, v| arr << "#{o}=\"#{v.to_s}\"" }
|
55
|
+
"<#{arr.join(' ')}>#{body}</#{tag}>"
|
56
|
+
end
|
57
|
+
|
58
|
+
def html_safe(text)
|
59
|
+
text
|
60
|
+
end
|
61
|
+
|
62
|
+
def html_safe?(text)
|
63
|
+
true
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module WrapIt
|
2
|
+
#
|
3
|
+
# Provides render function for Rails
|
4
|
+
#
|
5
|
+
# @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
|
6
|
+
#
|
7
|
+
module Renderer
|
8
|
+
def empty_html
|
9
|
+
''.html_safe
|
10
|
+
end
|
11
|
+
|
12
|
+
def html_safe(text)
|
13
|
+
text.html_safe
|
14
|
+
end
|
15
|
+
|
16
|
+
def html_safe?(text)
|
17
|
+
text.html_safe?
|
18
|
+
end
|
19
|
+
|
20
|
+
def superhtml(text)
|
21
|
+
text.to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def capture(*args, &block)
|
25
|
+
@template.capture(*args, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
def concat(*args, &block)
|
29
|
+
@template.concat(*args, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def content_tag(*args, &block)
|
33
|
+
@template.content_tag(*args, &block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def output_buffer(*args, &block)
|
37
|
+
@template.output_buffer(*args, &block)
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
# def self.included(base)
|
42
|
+
# puts "LOADED"
|
43
|
+
# base.class_eval do
|
44
|
+
# delegate :capture, :concat, :content_tag,
|
45
|
+
# :output_buffer, to: :@template
|
46
|
+
# protected :capture, :concat, :content_tag,
|
47
|
+
# :output_buffer
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module WrapIt
|
2
|
+
#
|
3
|
+
# Adds switches functionality
|
4
|
+
#
|
5
|
+
# @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
|
6
|
+
#
|
7
|
+
module Switches
|
8
|
+
def self.included(base)
|
9
|
+
base <= Base || fail(
|
10
|
+
TypeError,
|
11
|
+
"#{self.class.name} can be included only into WrapIt::Base subclasses"
|
12
|
+
)
|
13
|
+
extend DerivedAttributes
|
14
|
+
base.extend ClassMethods
|
15
|
+
base.after_initialize :switches_init
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def switches_init
|
21
|
+
switches = self.class.collect_derived(:@switches, {}, :merge)
|
22
|
+
keys = switches.keys
|
23
|
+
keys.each { |switch| instance_variable_set("@#{switch}", false) }
|
24
|
+
@options.keys.select { |o| keys.include?(o) }.each do |switch|
|
25
|
+
send("#{switches[switch][:name]}=", @options.delete(switch) == true)
|
26
|
+
end
|
27
|
+
@arguments.extract!(Symbol, and: [keys]).each do |switch|
|
28
|
+
send("#{switches[switch][:name]}=", true)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Class methods to include
|
34
|
+
#
|
35
|
+
module ClassMethods
|
36
|
+
#
|
37
|
+
# @dsl
|
38
|
+
# Adds `switch`. Switch is a boolean flag. When element created, creation
|
39
|
+
# arguments will be scanned for `Symbol`, that equals to `name`. If
|
40
|
+
# it founded, switch turned on. Also creation options inspected. If
|
41
|
+
# its contains `name: true` key-value pair, this pair removed from
|
42
|
+
# options and switch also turned on.
|
43
|
+
#
|
44
|
+
# This method also adds getter and setter for this switch in form `name?`
|
45
|
+
# and `name=` respectively.
|
46
|
+
#
|
47
|
+
# @param name [String, Symbol] Switch name. Converted to `Symbol`.
|
48
|
+
# @param options = {} [Hash] Switch options
|
49
|
+
# @options options [String, Symbol, Array<String, Symbol>] :html_class
|
50
|
+
# HTML class that will automatically added to element if switch is on
|
51
|
+
# or removed from element if switch id off.
|
52
|
+
# @options options [Symbol, Array<Symbol>] :aliases list of aliases.
|
53
|
+
# Warning! Values are not converted - pass only `Symbols` here.
|
54
|
+
# @yield [state] Runs block when switch state changed, gives it to block.
|
55
|
+
# @yieldparam state [Boolean] Whether switch is on or off.
|
56
|
+
# @yieldreturn [void]
|
57
|
+
#
|
58
|
+
# @return [void]
|
59
|
+
def switch(name, options = {}, &block)
|
60
|
+
options.symbolize_keys!
|
61
|
+
name = name.to_sym
|
62
|
+
options.merge!(block: block, name: name)
|
63
|
+
names = [name] + [[options[:aliases]] || []].flatten
|
64
|
+
var = "@#{name}".to_sym
|
65
|
+
define_method("#{name}?") { instance_variable_get(var) == true }
|
66
|
+
define_method("#{name}=") do |value|
|
67
|
+
instance_variable_set(var, value == true)
|
68
|
+
if value == true
|
69
|
+
options.key?(:html_class) && add_html_class(options[:html_class])
|
70
|
+
block.nil? || instance_exec(true, &block)
|
71
|
+
else
|
72
|
+
options.key?(:html_class) &&
|
73
|
+
remove_html_class(options[:html_class])
|
74
|
+
block.nil? || instance_exec(false, &block)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
@switches ||= {}
|
78
|
+
names.each { |n| @switches[n] = options }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module WrapIt
|
2
|
+
#
|
3
|
+
# TextContainer
|
4
|
+
#
|
5
|
+
# @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
|
6
|
+
#
|
7
|
+
module TextContainer
|
8
|
+
def self.included(base)
|
9
|
+
base.class_eval do
|
10
|
+
default_tag 'p'
|
11
|
+
|
12
|
+
after_initialize do
|
13
|
+
@body = @arguments.extract_first!(String) || empty_html
|
14
|
+
@body += @options[:body] || @options[:text] || empty_html
|
15
|
+
@options.delete(:body)
|
16
|
+
@options.delete(:text)
|
17
|
+
end
|
18
|
+
|
19
|
+
after_capture do
|
20
|
+
@content = html_safe(@body) + @content unless @body.nil?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|