wrap_it 0.2.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -0
- data/.yardopts +3 -0
- data/README.md +67 -66
- data/lib/wrap_it.rb +16 -16
- data/lib/wrap_it/arguments.rb +368 -0
- data/lib/wrap_it/base.rb +56 -47
- data/lib/wrap_it/callbacks.rb +24 -5
- data/lib/wrap_it/capture_array.rb +140 -0
- data/lib/wrap_it/container.rb +69 -25
- data/lib/wrap_it/derived_attributes.rb +22 -6
- data/lib/wrap_it/enums.rb +44 -34
- data/lib/wrap_it/frameworks.rb +7 -3
- data/lib/wrap_it/helpers.rb +66 -1
- data/lib/wrap_it/html.rb +149 -0
- data/lib/wrap_it/html_class.rb +164 -183
- data/lib/wrap_it/html_data.rb +28 -15
- data/lib/wrap_it/link.rb +40 -17
- data/lib/wrap_it/sections.rb +90 -2
- data/lib/wrap_it/switches.rb +33 -29
- data/lib/wrap_it/text_container.rb +83 -10
- data/lib/wrap_it/version.rb +2 -1
- data/spec/frameworks/log/development.log +2108 -0
- data/spec/integration/base_spec.rb +2 -2
- data/spec/integration/container_spec.rb +3 -3
- data/spec/integration/examples_spec.rb +16 -15
- data/spec/integration/text_container_spec.rb +3 -3
- data/spec/lib/arguments_array_spec.rb +37 -27
- data/spec/lib/arguments_spec.rb +153 -0
- data/spec/lib/base_spec.rb +2 -25
- data/spec/lib/callbacks_spec.rb +1 -1
- data/spec/lib/container_spec.rb +1 -1
- data/spec/lib/derived_attributes_spec.rb +1 -1
- data/spec/lib/enums_spec.rb +2 -3
- data/spec/lib/html_class_spec.rb +269 -80
- data/spec/lib/html_data_spec.rb +18 -12
- data/spec/lib/html_spec.rb +124 -0
- data/spec/lib/link_spec.rb +2 -2
- data/spec/lib/sections_spec.rb +1 -1
- data/spec/lib/switches_spec.rb +3 -3
- data/spec/lib/text_container_spec.rb +2 -2
- data/spec/support/example_groups/{wrap_it_example_group.rb → wrapped_example_group.rb} +5 -5
- data/wrap_it.gemspec +2 -0
- metadata +15 -8
- data/lib/wrap_it/arguments_array.rb +0 -128
- data/lib/wrap_it/module_helpers.rb +0 -23
data/lib/wrap_it/link.rb
CHANGED
@@ -1,6 +1,22 @@
|
|
1
1
|
module WrapIt
|
2
2
|
#
|
3
|
-
#
|
3
|
+
# HTML link element
|
4
|
+
#
|
5
|
+
# You can specify link by `link`, `href` or `url` option or by first String
|
6
|
+
# argument. Also includes {TextContainer} module, so you can specify link
|
7
|
+
# body with `text` or `body` option or by second String argument or inside
|
8
|
+
# block.
|
9
|
+
#
|
10
|
+
# @example usage
|
11
|
+
# link = WrapIt::Link.new(template, 'http://some.url', 'text')
|
12
|
+
# link.render # => '<a href="http://some.url">test</a>'
|
13
|
+
# link = WrapIt::Link.new(template, link: 'http://some.url', text: 'text')
|
14
|
+
# link.render # => '<a href="http://some.url">test</a>'
|
15
|
+
# link = WrapIt::Link.new(template, 'text', link: http://some.url')
|
16
|
+
# link.render # => '<a href="http://some.url">test</a>'
|
17
|
+
#
|
18
|
+
# @example in template
|
19
|
+
# <%= link 'http://some.url' do %>text<% end %>
|
4
20
|
#
|
5
21
|
# @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
|
6
22
|
#
|
@@ -9,33 +25,40 @@ module WrapIt
|
|
9
25
|
|
10
26
|
default_tag 'a'
|
11
27
|
|
28
|
+
option :link, if: %i(link href url)
|
29
|
+
|
30
|
+
# extract first string argument as link only if it not specified in options
|
31
|
+
argument(:link, first_only: true, after_options: true,
|
32
|
+
if: String, and: ->{ !option_provided?(:link, :href, :url) }
|
33
|
+
) do |_, v|
|
34
|
+
self.href = v
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# Retrieves current link
|
39
|
+
#
|
40
|
+
# @return [String] link
|
12
41
|
def href
|
13
|
-
|
42
|
+
html_attr[:href]
|
14
43
|
end
|
15
44
|
|
45
|
+
#
|
46
|
+
# Sets link
|
47
|
+
# @param value [String] link
|
48
|
+
#
|
49
|
+
# @return [String] setted link
|
16
50
|
def href=(value)
|
17
51
|
if value.is_a?(Hash)
|
18
|
-
|
52
|
+
WrapIt.rails? || fail(
|
19
53
|
ArgumentError,
|
20
54
|
'Hash links supported only in Rails env'
|
21
55
|
)
|
22
56
|
value = @template.url_for(value)
|
23
57
|
end
|
24
58
|
value.is_a?(String) || fail(ArgumentError, 'Wrong link type')
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
before_initialize do
|
29
|
-
link = @options[:link] || @options[:href] || @options[:url]
|
30
|
-
@options.delete(:link)
|
31
|
-
@options.delete(:href)
|
32
|
-
@options.delete(:url)
|
33
|
-
unless link.is_a?(String) || link.is_a?(Hash)
|
34
|
-
@block.nil? && tmp = @arguments.extract_first!(String)
|
35
|
-
link = @arguments.extract_first!(String)
|
36
|
-
tmp.nil? || @arguments.unshift(tmp)
|
37
|
-
end
|
38
|
-
link.nil? || self.href = link
|
59
|
+
html_attr[:href] = value
|
39
60
|
end
|
61
|
+
alias_method :link=, :href=
|
62
|
+
alias_method :url=, :href=
|
40
63
|
end
|
41
64
|
end
|
data/lib/wrap_it/sections.rb
CHANGED
@@ -1,12 +1,60 @@
|
|
1
1
|
module WrapIt
|
2
2
|
#
|
3
|
-
#
|
3
|
+
# Sections is a smart way to make complex components with inheritance.
|
4
|
+
#
|
5
|
+
# Sections is just array of named HTML markup pieces. You can place any
|
6
|
+
# section before or after another at class level and change their content
|
7
|
+
# at instance level.
|
8
|
+
#
|
9
|
+
# Each component have three stages. First is initialization, then sections
|
10
|
+
# capturing and rendering. You can change any sections content until
|
11
|
+
# rendering stage begins. Finally, renderer joins all sections in order,
|
12
|
+
# that they have at render time.
|
13
|
+
#
|
14
|
+
# {WrapIt::Base} provides following sections: main section is `:content`.
|
15
|
+
# All text from block captured there. `:render_arguments` and `:render_block`
|
16
|
+
# also provided, so arguments and block passed to render method captured
|
17
|
+
# here.
|
18
|
+
#
|
19
|
+
# Access to sections at instance level performed throw hash-like getter and
|
20
|
+
# setter ([] and []=) of self.
|
21
|
+
#
|
22
|
+
# With this functionality you can easy organize you inheritance, so any
|
23
|
+
# descendant can change sections order or any section content without
|
24
|
+
# changes to unrelated sections.
|
25
|
+
#
|
26
|
+
# @example sections usage
|
27
|
+
# class IconedButton < WrapIt::Base
|
28
|
+
# include TextContainer
|
29
|
+
# html_class 'btn'
|
30
|
+
# section :icon
|
31
|
+
# place :icon, before: :content
|
32
|
+
#
|
33
|
+
# after_capture do
|
34
|
+
# self[:icon] = html_safe('<i class="my-icon"></i>')
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# class RightIconedButton < IconedButton
|
39
|
+
# place :icon, after: :content
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# b1 = IconedButton.new(template, 'text')
|
43
|
+
# b2 = RightIconedButton.new(template, 'text')
|
44
|
+
# b1.render # => '<div class="btn"><i class="my-icon"></i>text</div>'
|
45
|
+
# b2.render # => '<div class="btn">text<i class="my-icon"></i></div>'
|
4
46
|
#
|
5
47
|
# @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
|
6
48
|
#
|
7
49
|
module Sections
|
50
|
+
# Documentation includes
|
51
|
+
# @!parse extend Sections::ClassMethods
|
52
|
+
|
53
|
+
# module implementation
|
54
|
+
|
8
55
|
extend DerivedAttributes
|
9
56
|
|
57
|
+
#
|
10
58
|
def self.included(base)
|
11
59
|
base == Base || fail(
|
12
60
|
TypeError,
|
@@ -15,6 +63,11 @@ module WrapIt
|
|
15
63
|
base.extend ClassMethods
|
16
64
|
end
|
17
65
|
|
66
|
+
#
|
67
|
+
# Retrieves specified section content
|
68
|
+
# @param name [Symbol] section name
|
69
|
+
#
|
70
|
+
# @return [String] section content
|
18
71
|
def [](name)
|
19
72
|
@section_names ||= self.class.sections
|
20
73
|
return nil unless @section_names.include?(name)
|
@@ -22,6 +75,12 @@ module WrapIt
|
|
22
75
|
@sections[name] ||= empty_html
|
23
76
|
end
|
24
77
|
|
78
|
+
#
|
79
|
+
# Sets specified section content
|
80
|
+
# @param name [Symbol] section name
|
81
|
+
# @param value [String] content
|
82
|
+
#
|
83
|
+
# @return [String] section content
|
25
84
|
def []=(name, value)
|
26
85
|
@section_names ||= self.class.sections
|
27
86
|
return unless @section_names.include?(name)
|
@@ -30,13 +89,24 @@ module WrapIt
|
|
30
89
|
end
|
31
90
|
|
32
91
|
#
|
33
|
-
#
|
92
|
+
# {Sections} class methods
|
34
93
|
#
|
35
94
|
module ClassMethods
|
95
|
+
#
|
96
|
+
# Retrieves all sections, including ancestors
|
97
|
+
#
|
98
|
+
# @return [Array<Symbol>] array of sections
|
36
99
|
def sections
|
37
100
|
collect_derived(:@sections)
|
38
101
|
end
|
39
102
|
|
103
|
+
#
|
104
|
+
# Defines new section or sections. Places its to end of section list
|
105
|
+
#
|
106
|
+
# @overload section([name, ...])
|
107
|
+
# @param name [Symbol, String] section name
|
108
|
+
#
|
109
|
+
# @return [void]
|
40
110
|
def section(*args)
|
41
111
|
@sections ||= []
|
42
112
|
args.flatten.each do |name|
|
@@ -49,6 +119,10 @@ module WrapIt
|
|
49
119
|
end
|
50
120
|
end
|
51
121
|
|
122
|
+
#
|
123
|
+
# Retrieves section names in current order
|
124
|
+
#
|
125
|
+
# @return [Array<Symbol>] ordered sections array
|
52
126
|
def placement
|
53
127
|
@placement ||=
|
54
128
|
if self == Base
|
@@ -59,6 +133,20 @@ module WrapIt
|
|
59
133
|
end
|
60
134
|
end
|
61
135
|
|
136
|
+
#
|
137
|
+
# Places specific section in specified place
|
138
|
+
#
|
139
|
+
# @overload place(src, to)
|
140
|
+
# @param src [Symbol] section name to place
|
141
|
+
# @param to [Hash] single key-value hash. Key can be `:before` or
|
142
|
+
# `after`, value can be `:begin`, `:end` or section name
|
143
|
+
#
|
144
|
+
# @overload place(src, at, dst)
|
145
|
+
# @param src [Symbol] section name to place
|
146
|
+
# @param at [Symbol] can be `:before` or `:after`
|
147
|
+
# @param dst [Symbol] can be `:begin`, `:end` or section name
|
148
|
+
#
|
149
|
+
# @return [void]
|
62
150
|
def place(src, at, dst = nil)
|
63
151
|
if dst == nil && at.is_a?(Hash) && at.keys.size == 1
|
64
152
|
dst = at.values[0]
|
data/lib/wrap_it/switches.rb
CHANGED
@@ -5,40 +5,28 @@ module WrapIt
|
|
5
5
|
# @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
|
6
6
|
#
|
7
7
|
module Switches
|
8
|
+
# Documentation includes
|
9
|
+
# @!parse extend Switches::ClassMethods
|
10
|
+
|
11
|
+
# module implementation
|
12
|
+
|
8
13
|
extend DerivedAttributes
|
9
14
|
|
15
|
+
#
|
10
16
|
def self.included(base)
|
11
17
|
base == Base || fail(
|
12
18
|
TypeError,
|
13
19
|
"#{self.class.name} can be included only into WrapIt::Base"
|
14
20
|
)
|
15
21
|
base.extend ClassMethods
|
16
|
-
base.
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def switches_init
|
22
|
-
@switches = {}
|
23
|
-
keys = switches.keys
|
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
|
-
def switches
|
33
|
-
@switches_hash ||= self.class.collect_derived(:@switches, {}, :merge)
|
22
|
+
base.before_initialize { @switches = {} }
|
34
23
|
end
|
35
24
|
|
36
25
|
#
|
37
|
-
#
|
26
|
+
# {Switches} class methods
|
38
27
|
#
|
39
28
|
module ClassMethods
|
40
29
|
#
|
41
|
-
# @dsl
|
42
30
|
# Adds `switch`. Switch is a boolean flag. When element created, creation
|
43
31
|
# arguments will be scanned for `Symbol`, that equals to `name`. If
|
44
32
|
# it founded, switch turned on. Also creation options inspected. If
|
@@ -57,11 +45,11 @@ module WrapIt
|
|
57
45
|
# on or removed in other case.
|
58
46
|
#
|
59
47
|
# @param name [String, Symbol] Switch name. Converted to `Symbol`.
|
60
|
-
# @param
|
61
|
-
# @options
|
48
|
+
# @param options [Hash] Switch options
|
49
|
+
# @option options [true, String, Symbol, Array<String, Symbol>] :html_class
|
62
50
|
# HTML classes list that will automatically added to element if switch
|
63
51
|
# is on or removed from element if switch id off.
|
64
|
-
# @options
|
52
|
+
# @option options [Symbol, Array<Symbol>] :aliases list of aliases.
|
65
53
|
# Warning! Values are not converted - pass only `Symbols` here.
|
66
54
|
# @yield [state] Runs block when switch state changed, gives it to block.
|
67
55
|
# @yieldparam state [Boolean] Whether switch is on or off.
|
@@ -83,11 +71,28 @@ module WrapIt
|
|
83
71
|
end
|
84
72
|
end
|
85
73
|
end
|
86
|
-
|
74
|
+
|
87
75
|
define_method("#{name}?") { @switches[name] == true }
|
88
76
|
define_method("#{name}=", &Switches.setter(name, &block))
|
89
77
|
@switches ||= {}
|
90
|
-
|
78
|
+
|
79
|
+
@switches[name] = options
|
80
|
+
|
81
|
+
o_params = {}
|
82
|
+
a_params = { if: Symbol, and: name }
|
83
|
+
if options.key?(:aliases)
|
84
|
+
aliases = [options[:aliases]].flatten.compact
|
85
|
+
o_params[:if] = [name] + aliases
|
86
|
+
a_params[:and] = [name] + aliases
|
87
|
+
end
|
88
|
+
|
89
|
+
option(name, **o_params) do |_, v|
|
90
|
+
send("#{options[:name]}=", v == true)
|
91
|
+
end
|
92
|
+
|
93
|
+
argument(name, **a_params) do |_, _|
|
94
|
+
send("#{options[:name]}=", true)
|
95
|
+
end
|
91
96
|
end
|
92
97
|
end
|
93
98
|
|
@@ -96,19 +101,18 @@ module WrapIt
|
|
96
101
|
#
|
97
102
|
# Makes switch setter block
|
98
103
|
# @param name [String] switch name
|
99
|
-
# @param &block [Proc] switch block
|
100
104
|
#
|
101
105
|
# @return [Proc] switch setter block
|
102
106
|
def self.setter(name, &block)
|
103
107
|
proc do |value|
|
104
|
-
opts = switches[name]
|
108
|
+
opts = self.class.collect_derived(:@switches, {}, :merge)[name]
|
105
109
|
cb_return = block.nil? || instance_exec(value == true, &block)
|
106
110
|
unless cb_return == false
|
107
111
|
@switches[name] = value == true
|
108
112
|
if value == true
|
109
|
-
opts.key?(:html_class) &&
|
113
|
+
opts.key?(:html_class) && html_class << opts[:html_class]
|
110
114
|
else
|
111
|
-
opts.key?(:html_class) &&
|
115
|
+
opts.key?(:html_class) && html_class.delete(*opts[:html_class])
|
112
116
|
end
|
113
117
|
end
|
114
118
|
end
|
@@ -1,30 +1,103 @@
|
|
1
1
|
module WrapIt
|
2
2
|
#
|
3
|
-
#
|
3
|
+
# Provides functionality for text-contained components.
|
4
|
+
#
|
5
|
+
# Text can be captured from `:text` or `:body` option, or as first unparsed
|
6
|
+
# String argument, or in block, provided to constructor.
|
7
|
+
#
|
8
|
+
# If block given, text will be captured from it in priority, so String
|
9
|
+
# arguments and options will not parsed. You can cancel this manner by
|
10
|
+
# calling {ClassMethods#text_in_block text_in_block(false)} method.
|
11
|
+
#
|
12
|
+
# This module adds `body` section before base `content` section.
|
4
13
|
#
|
5
14
|
# @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
|
6
15
|
#
|
7
16
|
module TextContainer
|
17
|
+
#
|
8
18
|
def self.included(base)
|
9
19
|
base.class_eval do
|
20
|
+
extend ClassMethods
|
21
|
+
|
10
22
|
default_tag 'p', false
|
11
23
|
|
24
|
+
option(:body, if: %i(body text)) { |_, v| body << v }
|
25
|
+
argument(:body, first_only: true, after_options: true,
|
26
|
+
if: String,
|
27
|
+
and: ->{ !block_provided? || !text_in_block? }) do |_, v|
|
28
|
+
self.class.html_safe? && v = html_safe(v)
|
29
|
+
body << v
|
30
|
+
end
|
31
|
+
|
12
32
|
section :body
|
13
33
|
place :body, :before, :content
|
14
34
|
|
15
|
-
after_initialize do
|
16
|
-
@body = @arguments.extract_first!(String) || empty_html
|
17
|
-
@body += @options[:body] || @options[:text] || empty_html
|
18
|
-
@options.delete(:body)
|
19
|
-
@options.delete(:text)
|
20
|
-
end
|
21
|
-
|
22
35
|
after_capture do
|
23
|
-
self[:body] = html_safe(@body) unless @body.nil?
|
36
|
+
self[:body] = html_safe(@body) unless @body.nil? || @body.empty?
|
24
37
|
end
|
25
38
|
end
|
26
39
|
end
|
27
40
|
|
28
|
-
|
41
|
+
#
|
42
|
+
# Retrieves body text
|
43
|
+
#
|
44
|
+
# @return [String] text
|
45
|
+
def body
|
46
|
+
@body ||= empty_html
|
47
|
+
end
|
48
|
+
|
49
|
+
module ClassMethods
|
50
|
+
#
|
51
|
+
# Sets priotiy of text source
|
52
|
+
#
|
53
|
+
# @param value [Boolean] `true` means if block present - text will
|
54
|
+
# be captured from there. `false` means first to inspect arguments and
|
55
|
+
# options and if it ommited retirieve text from block.
|
56
|
+
#
|
57
|
+
# @return [Boolean] current value
|
58
|
+
def text_in_block(value = nil)
|
59
|
+
if value.nil?
|
60
|
+
@text_in_block.nil? && @text_in_block = true
|
61
|
+
@text_in_block
|
62
|
+
else
|
63
|
+
@text_in_block = value == true
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Retrieves block priority
|
69
|
+
#
|
70
|
+
# @return [Boolean] current value
|
71
|
+
def text_in_block?
|
72
|
+
@text_in_block.nil? && @text_in_block = true
|
73
|
+
@text_in_block
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
# Sets whether text from arguments are html-safe
|
78
|
+
# @param value [Boolean] `true` means that text from arguments have
|
79
|
+
# proper markup and component will mark it as save via html_safe
|
80
|
+
# method. `flase` means, that this values can contain unsafe content,
|
81
|
+
# so user should make html-safe string by itself.
|
82
|
+
#
|
83
|
+
# @return [Boolean] current value
|
84
|
+
def html_safe(value = nil)
|
85
|
+
if value.nil?
|
86
|
+
@html_safe.nil? && @html_safe = true
|
87
|
+
@html_safe
|
88
|
+
else
|
89
|
+
@html_safe = value == true
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# Retrieves whether text from attributes are html-safe
|
95
|
+
#
|
96
|
+
# @return [Boolean] current value
|
97
|
+
def html_safe?
|
98
|
+
@html_safe.nil? && @html_safe = true
|
99
|
+
@html_safe
|
100
|
+
end
|
101
|
+
end
|
29
102
|
end
|
30
103
|
end
|