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/html_class.rb
CHANGED
@@ -1,233 +1,214 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
1
3
|
module WrapIt
|
2
4
|
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
5
|
+
# Provides array-like access to HTML classes.
|
6
|
+
#
|
7
|
+
# This class delegate allmost all methods to underlying array with some
|
8
|
+
# value checking and modification. Also it restrict a list of methods,
|
9
|
+
# exposed below becouse call to theese methods unusefull in context of HTML
|
10
|
+
# class list.
|
11
|
+
#
|
12
|
+
# Some methods, thats described in this document have different manner.
|
13
|
+
# See each method description for details.
|
14
|
+
#
|
15
|
+
# All other methods can be used as with standard array
|
16
|
+
#
|
17
|
+
# Restricted methods: assoc, bsearch, combination, compact, compact!, fill,
|
18
|
+
# flatten, flatten!, insert, pack, permutation, product, rassoc,
|
19
|
+
# repeated_combination, rotate, repeated_permutation, reverse reverse!,
|
20
|
+
# reverse_each, sample, rotate!, shuffle, shuffle!, sort, sort!, sort_by!,
|
21
|
+
# transpose, uniq, uniq!, zip, flat_map, max, max_by, min, min_by, minmax,
|
22
|
+
# minmax_by
|
6
23
|
#
|
7
24
|
# @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
|
8
25
|
#
|
9
|
-
|
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"
|
16
|
-
)
|
17
|
-
base.extend ClassMethods
|
18
|
-
end
|
19
|
-
|
26
|
+
class HTMLClass < DelegateClass(Array)
|
20
27
|
#
|
21
|
-
#
|
22
|
-
#
|
28
|
+
# Sanitizes and normalizes HTML class. Makes array of classes flatten,
|
29
|
+
# removes all duplicates, splits spaced strings.
|
23
30
|
#
|
24
|
-
# @
|
25
|
-
#
|
31
|
+
# @param values [Object] can be a symbol, string, array of symbols and
|
32
|
+
# strings, array of strings, strings can contains spaces.
|
26
33
|
#
|
27
|
-
# @return [Array<String>] sanitized HTML classes
|
28
|
-
def self.sanitize(*
|
29
|
-
|
34
|
+
# @return [Array<String>] sanitized list of HTML classes
|
35
|
+
def self.sanitize(*values)
|
36
|
+
values
|
30
37
|
.flatten
|
31
|
-
.
|
32
|
-
|
38
|
+
.each_with_object([]) do |i, a|
|
39
|
+
a << i.to_s if i.is_a?(String) || i.is_a?(Symbol)
|
40
|
+
end
|
41
|
+
.join(' ')
|
42
|
+
.strip
|
43
|
+
.split(/\s+/)
|
33
44
|
.uniq
|
34
45
|
end
|
35
46
|
|
36
|
-
|
37
|
-
|
38
|
-
#
|
39
|
-
# @return [Array<String>] array of html classes of element.
|
40
|
-
def html_class
|
41
|
-
@options[:class]
|
47
|
+
def initialize(value = [])
|
48
|
+
super(HTMLClass.sanitize(value))
|
42
49
|
end
|
43
50
|
|
44
|
-
#
|
45
|
-
|
46
|
-
#
|
47
|
-
|
48
|
-
|
49
|
-
|
51
|
+
# Array overrides
|
52
|
+
|
53
|
+
# with array argument and new array return
|
54
|
+
%i(& + - concat |).each do |method|
|
55
|
+
define_method method do |values|
|
56
|
+
HTMLClass.new(__getobj__.send(method, HTMLClass.sanitize(values)))
|
57
|
+
end
|
50
58
|
end
|
51
59
|
|
52
|
-
#
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
#
|
59
|
-
# @example
|
60
|
-
# element.html_class = [:a, 'b', ['c', :d, 'a']]
|
61
|
-
# element.html_class #=> ['a', 'b', 'c', 'd']
|
62
|
-
def html_class=(value)
|
63
|
-
@options[:class] = []
|
64
|
-
add_html_class(value)
|
60
|
+
# array process, returning new array
|
61
|
+
%i(collect drop_while map reject select).each do |method|
|
62
|
+
define_method method do |&block|
|
63
|
+
result = __getobj__.send(method, &block)
|
64
|
+
result.is_a?(Array) ? HTMLClass.new(result) : result
|
65
|
+
end
|
65
66
|
end
|
66
67
|
|
67
|
-
#
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
#
|
75
|
-
# @example
|
76
|
-
# element.html_class = 'a'
|
77
|
-
# element.add_html_class :b, :c, ['d', :c, :e, 'a']
|
78
|
-
# element.html_class #=> ['a', 'b', 'c', 'd', 'e']
|
79
|
-
def add_html_class(*args)
|
80
|
-
if @options.key?(:class)
|
81
|
-
@options[:class].is_a?(Array) || options[:class] = [options[:class]]
|
82
|
-
args += @options[:class]
|
68
|
+
# bang! array process
|
69
|
+
%i(collect! map! reject!).each do |method|
|
70
|
+
define_method method do |&block|
|
71
|
+
obj = __getobj__
|
72
|
+
result = obj.send(method, &block)
|
73
|
+
obj.replace(HTMLClass.sanitize(obj))
|
74
|
+
result.is_a?(Array) ? self : result
|
83
75
|
end
|
84
|
-
@options[:class] = HTMLClass.sanitize(*args)
|
85
|
-
self # allow chaining
|
86
76
|
end
|
87
77
|
|
88
|
-
#
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
# @return [self]
|
94
|
-
#
|
95
|
-
# @example
|
96
|
-
# element.add_html_class %w(a b c d e)
|
97
|
-
# element.remove_html_class :b, ['c', :e]
|
98
|
-
# element.html_class #=> ['a', 'd']
|
99
|
-
def remove_html_class(*args)
|
100
|
-
args.flatten!
|
101
|
-
re = []
|
102
|
-
args.reject! { |c| c.is_a?(Regexp) && re << c && true }
|
103
|
-
args = args.uniq.map { |c| c.to_s }
|
104
|
-
args.size > 0 && @options[:class].reject! { |c| args.include?(c) }
|
105
|
-
re.is_a?(Array) && re.each do |r|
|
106
|
-
@options[:class].reject! { |c| r.match(c) }
|
78
|
+
# non-bang array process, returning self
|
79
|
+
%i(each each_index keep_if select!).each do |method|
|
80
|
+
define_method method do |&block|
|
81
|
+
result = __getobj__.send(method, &block)
|
82
|
+
result.is_a?(Array) ? self : result
|
107
83
|
end
|
108
|
-
self # allow chaining
|
109
84
|
end
|
110
85
|
|
86
|
+
%i(<< concat).each do |method|
|
87
|
+
define_method method do |values|
|
88
|
+
data = __getobj__ + HTMLClass.sanitize(values)
|
89
|
+
__setobj__(data.uniq)
|
90
|
+
self
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# with any args, returning some obj or new array
|
95
|
+
%i([] drop first last pop shift slice! values_at).each do |method|
|
96
|
+
define_method method do |*args|
|
97
|
+
result = __getobj__.send(method, *args)
|
98
|
+
result.is_a?(Array) ? HTMLClass.new(result) : result
|
99
|
+
end
|
100
|
+
end
|
101
|
+
alias_method :slice, :[]
|
102
|
+
|
103
|
+
# @private
|
104
|
+
def clear
|
105
|
+
__getobj__.clear
|
106
|
+
self
|
107
|
+
end
|
108
|
+
|
109
|
+
|
111
110
|
#
|
112
|
-
#
|
113
|
-
# specified in method arguments.
|
114
|
-
#
|
115
|
-
# There are two forms of method call: with list of conditions as arguments
|
116
|
-
# and with block for comparing. Method makes comparison with html class
|
117
|
-
# untill first `true` return value or end of list. All conditions should
|
118
|
-
# be satisfied for `true` return of this method.
|
119
|
-
#
|
120
|
-
# In first form, each argument treated as condition. Condition can be a
|
121
|
-
# `Regexp`, so html classes of element tested for matching to that
|
122
|
-
# regular expression. If condition is an `Array` then every class will be
|
123
|
-
# tested for presence in this array. If condition is `Symbol` or `String`
|
124
|
-
# classes will be compared with it via equality operator `==`.
|
111
|
+
# Removes elements from list by some conditions.
|
125
112
|
#
|
126
|
-
#
|
127
|
-
# block called with html class as argument. Block return value then used.
|
113
|
+
# See {#index} for condition details
|
128
114
|
#
|
129
|
-
# @overload
|
130
|
-
#
|
131
|
-
#
|
115
|
+
# @overload delete([cond, ...], &block)
|
116
|
+
# @param cond [Symbol, String, Array<String>, Regexp] [description]
|
117
|
+
# @param &block [Proc] searching block
|
132
118
|
#
|
133
|
-
# @
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
119
|
+
# @return [self]
|
120
|
+
def delete(*args, &block)
|
121
|
+
obj = __getobj__
|
122
|
+
args.each do |x|
|
123
|
+
i = index(x)
|
124
|
+
next if i.nil? || i.is_a?(Enumerator)
|
125
|
+
obj.delete_at(i)
|
126
|
+
end
|
127
|
+
unless block.nil?
|
128
|
+
i = index(&block)
|
129
|
+
i.nil? || obj.delete_at(i)
|
130
|
+
end
|
131
|
+
self
|
132
|
+
end
|
133
|
+
|
138
134
|
#
|
139
|
-
#
|
135
|
+
# Searches HTML classes by conditions
|
140
136
|
#
|
141
|
-
#
|
142
|
-
#
|
143
|
-
# element.html_class?(:a) #=> true
|
144
|
-
# element.html_class?(:d) #=> false
|
145
|
-
# element.html_class?(:a, 'b') #=> true
|
146
|
-
# element.html_class?(:a, :d) #=> false
|
137
|
+
# Conditions can be a Symbol, String, Array of strings or Regexp. Or you
|
138
|
+
# can provide block for searching.
|
147
139
|
#
|
148
|
-
#
|
149
|
-
#
|
150
|
-
#
|
151
|
-
# element.html_class?(/some/, /bad/) #=> false
|
152
|
-
# element.html_class?(/some/, :test) #=> true
|
140
|
+
# For Strings and Symbols array-like search used (symbols converted to
|
141
|
+
# strings). For Array conditions, any value from this array will match.
|
142
|
+
# For Regexp - regular expression matcher will used.
|
153
143
|
#
|
154
|
-
# @
|
155
|
-
#
|
156
|
-
# element.html_class?(%w(a d)) #=> true
|
157
|
-
# element.html_class?(%w(e d)) #=> false
|
144
|
+
# @param value [nil, Symbol, String, Array<String>, Regexp] condition
|
145
|
+
# @param block [Proc] searching block
|
158
146
|
#
|
159
|
-
# @
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
147
|
+
# @return [nil, Number] index of finded item or nil
|
148
|
+
def index(value = nil, &block)
|
149
|
+
value.is_a?(Symbol) && value = value.to_s
|
150
|
+
value.is_a?(Array) && value.map! { |x| x.to_s }
|
151
|
+
case
|
152
|
+
when value.is_a?(Regexp) then __getobj__.index { |x| value =~ x }
|
153
|
+
when value.is_a?(Array) then __getobj__.index { |x| value.include?(x) }
|
154
|
+
when block_given? then __getobj__.index(&block)
|
155
|
+
when value.nil? then __getobj__.index
|
156
|
+
else __getobj__.index(value)
|
157
|
+
end
|
164
158
|
end
|
159
|
+
alias_method :rindex, :index
|
165
160
|
|
166
161
|
#
|
167
|
-
# Determines whether
|
168
|
-
#
|
162
|
+
# Determines whether HTML classes have class, matching conditions
|
163
|
+
#
|
164
|
+
# @overload include?([cond, ...])
|
165
|
+
# @param cond [Symbol, String, Array<String>, Regexp] [description]
|
169
166
|
#
|
170
|
-
# @
|
171
|
-
def
|
172
|
-
args.all?
|
167
|
+
# @return [Boolean] whether HTML classes include specified class
|
168
|
+
def include?(*args)
|
169
|
+
args.all? do |x|
|
170
|
+
x.is_a?(Proc) ? !index(&x).nil? : !index(x).nil?
|
171
|
+
end
|
173
172
|
end
|
174
173
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
174
|
+
#
|
175
|
+
# Combines all classes, ready to insert in HTML.
|
176
|
+
#
|
177
|
+
# Actually just join all values with spaces
|
178
|
+
#
|
179
|
+
# @return [String] html string
|
180
|
+
def to_html
|
181
|
+
__getobj__.join(' ')
|
179
182
|
end
|
180
183
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
@options[:class].send(with, &block)
|
186
|
-
else
|
187
|
-
case
|
188
|
-
when value.is_a?(Regexp)
|
189
|
-
@options[:class].send(with) { |c| value.match(c) }
|
190
|
-
when value.is_a?(String) || value.is_a?(Symbol)
|
191
|
-
@options[:class].send(with) { |c| value.to_s == c }
|
192
|
-
when value.is_a?(Array)
|
193
|
-
@options[:class].send(with) { |c| value.include?(c) }
|
194
|
-
else
|
195
|
-
false
|
196
|
-
end
|
184
|
+
%i(replace).each do |method|
|
185
|
+
define_method method do |*values|
|
186
|
+
__getobj__.send(method, HTMLClass.sanitize(values))
|
187
|
+
self
|
197
188
|
end
|
198
189
|
end
|
199
190
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
# @dsl
|
206
|
-
# Adds default html classes, thats are automatically added when element
|
207
|
-
# created.
|
208
|
-
# @override html_class([html_class, ...])
|
209
|
-
# @param html_class [String, Symbol, Array<String, Symbol>] HTML class.
|
210
|
-
# Converted to `String`
|
211
|
-
#
|
212
|
-
# @return [void]
|
213
|
-
def html_class(*args)
|
214
|
-
@html_class.nil? || args += @html_class
|
215
|
-
@html_class = HTMLClass.sanitize(*args)
|
191
|
+
%i(push unshift).each do |method|
|
192
|
+
define_method method do |*values|
|
193
|
+
__getobj__.send(method, *HTMLClass.sanitize(values))
|
194
|
+
__getobj__.uniq!
|
195
|
+
self
|
216
196
|
end
|
197
|
+
end
|
217
198
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
)
|
229
|
-
@html_class_prefix = prefix.to_s
|
199
|
+
# Restricted functions
|
200
|
+
%i(
|
201
|
+
* []= assoc bsearch combination compact compact! fill flatten flatten!
|
202
|
+
insert pack permutation product rassoc repeated_combination rotate
|
203
|
+
repeated_permutation reverse reverse! reverse_each sample rotate! shuffle
|
204
|
+
shuffle! sort sort! sort_by! transpose uniq uniq! zip flat_map max max_by
|
205
|
+
min min_by minmax minmax_by
|
206
|
+
).each do |method|
|
207
|
+
define_method(method) do
|
208
|
+
raise "Method #{method} is not supported for HTMLClass"
|
230
209
|
end
|
231
210
|
end
|
211
|
+
|
212
|
+
# Enumerable overrides
|
232
213
|
end
|
233
214
|
end
|
data/lib/wrap_it/html_data.rb
CHANGED
@@ -1,25 +1,38 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
1
3
|
module WrapIt
|
2
4
|
#
|
3
|
-
# Provides
|
5
|
+
# Provides hash-like access to HTML data.
|
4
6
|
#
|
5
7
|
# @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
|
6
8
|
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
def
|
16
|
-
|
17
|
-
|
9
|
+
class HTMLData < DelegateClass(Hash)
|
10
|
+
#
|
11
|
+
# Sanitizes html data
|
12
|
+
#
|
13
|
+
# @overload sanitize(values = {})
|
14
|
+
# @param values [Hash] hash to sanitize
|
15
|
+
#
|
16
|
+
# @return [Hash] sanitized hash
|
17
|
+
def self.sanitize(**values)
|
18
|
+
Hash[values
|
19
|
+
.map do |k, v|
|
20
|
+
k = k.to_s
|
21
|
+
if k.include?('-')
|
22
|
+
k, n = k.split(/-/, 2)
|
23
|
+
v = sanitize(n.to_sym => v)
|
24
|
+
else
|
25
|
+
k = k.downcase.gsub(/[^a-z0-9_]+/, '').gsub(/\A\d+/, '')
|
26
|
+
v = v.is_a?(Hash) ? sanitize(v) : v.to_s
|
27
|
+
end
|
28
|
+
k.empty? ? nil : [k.to_sym, v]
|
29
|
+
end
|
30
|
+
.compact
|
31
|
+
]
|
18
32
|
end
|
19
33
|
|
20
|
-
def
|
21
|
-
|
22
|
-
@options[:data].delete(name.to_sym)
|
34
|
+
def initialize(**value)
|
35
|
+
super(HTMLData.sanitize(**value))
|
23
36
|
end
|
24
37
|
end
|
25
38
|
end
|