wrap_it 0.2.0 → 1.0.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 +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
|