paggio 0.2.3 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 3a11d9925363cd6d0477a1b04cb820aa31b7d312
4
- data.tar.gz: 5a0240a9f6e6ac843d69e182b081ffcd53233852
2
+ SHA256:
3
+ metadata.gz: 2fefeb82ee3a488498bd68beb67ff153d799ed90d0048ab6431548af06bae9b3
4
+ data.tar.gz: b4dad7ad19b3976bb1b92fab92cde617338e4d6e02a777891ed04199bb7a5695
5
5
  SHA512:
6
- metadata.gz: 906b709105eee61adf45ff4d672125b2d9c14223833a1d92558c30f6a9eff2fc0f05ed5f370175f1ee09935618751d4b0aa1264f9e9d3eeeac8143cabdbe3963
7
- data.tar.gz: ea71aca4f89688852800f4af745297a2e3d714367fb8aa23b080b448b28d19003e008f074559a9743c8947e86ccbea792acaca7cb82b31b78359bf013bc7e6c0
6
+ metadata.gz: 8e8004f7ba60ad66eae1d64f1be17766f544459aa87b0876bffe3cef9c17997b6dfb16ae96192c33ead174efb146f9b2827245aa3f144b188296bfbb1f95f81a
7
+ data.tar.gz: f37fab29e7fa8404c2f6adec4b711b3a4b644b691fe40065711501e28b12e9369e7e8a370f6174d45bef8cc233c3ab7683cf2b571b55a92220f53f277120b20f
@@ -0,0 +1,29 @@
1
+ name: Tests
2
+ on:
3
+ push:
4
+ branches:
5
+ - master
6
+ - "*-stable"
7
+ - "*/ci-check"
8
+ pull_request:
9
+
10
+ jobs:
11
+ tests:
12
+ name: Tests
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ ruby: [2.6, 2.7, 3.0]
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - name: Checkout code
20
+ uses: actions/checkout@v2
21
+
22
+ - name: Setup Ruby
23
+ uses: ruby/setup-ruby@v1
24
+ with:
25
+ ruby-version: ${{ matrix.ruby }}
26
+ bundler-cache: true
27
+
28
+ - name: Run tests
29
+ run: bundle exec rake
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ gem 'rake'
5
+ gem 'rspec'
data/Gemfile.lock ADDED
@@ -0,0 +1,29 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ paggio (0.3.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.2.5)
10
+ rake (10.1.1)
11
+ rspec (2.14.1)
12
+ rspec-core (~> 2.14.0)
13
+ rspec-expectations (~> 2.14.0)
14
+ rspec-mocks (~> 2.14.0)
15
+ rspec-core (2.14.8)
16
+ rspec-expectations (2.14.5)
17
+ diff-lcs (>= 1.1.3, < 2.0)
18
+ rspec-mocks (2.14.6)
19
+
20
+ PLATFORMS
21
+ ruby
22
+
23
+ DEPENDENCIES
24
+ paggio!
25
+ rake
26
+ rspec
27
+
28
+ BUNDLED WITH
29
+ 2.1.4
data/Rakefile CHANGED
@@ -1,16 +1,10 @@
1
1
  #! /usr/bin/env ruby
2
- require 'rake'
3
2
 
4
- task :default => [:install, :test]
3
+ require 'bundler/setup'
4
+ require 'bundler/gem_tasks'
5
+ require 'rake'
5
6
 
6
- task :install do
7
- sh 'gem install --no-force rspec'
8
- sh 'gem build *.gemspec'
9
- sh 'gem install *.gem'
10
- end
7
+ require "rspec/core/rake_task"
8
+ RSpec::Core::RakeTask.new(:rspec)
11
9
 
12
- task :test do
13
- FileUtils.cd 'spec' do
14
- sh 'rspec css_spec.rb --backtrace --color --format doc'
15
- end
16
- end
10
+ task :default => :rspec
@@ -0,0 +1,54 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
+ #
8
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
+ #++
10
+
11
+ class Paggio; class CSS < BasicObject
12
+
13
+ class Animation < BasicObject
14
+ class Step < BasicObject
15
+ attr_reader :value
16
+
17
+ def initialize(value)
18
+ @value = value
19
+ @definition = Definition.new
20
+ end
21
+
22
+ def method_missing(*args, &block)
23
+ @definition.__send__(*args, &block)
24
+ end
25
+ end
26
+
27
+ attr_reader :name, :steps
28
+
29
+ def initialize(name)
30
+ @name = name
31
+ @steps = []
32
+ end
33
+
34
+ def step(value, &block)
35
+ @steps << Step.new(value)
36
+ block.call
37
+ end
38
+
39
+ def from(value, &block)
40
+ @steps << Step.new(0.%)
41
+ block.call
42
+ end
43
+
44
+ def to(value, &block)
45
+ @steps << Step.new(100.%)
46
+ block.call
47
+ end
48
+
49
+ def method_missing(*args, &block)
50
+ @steps.last.__send__(*args, &block)
51
+ end
52
+ end
53
+
54
+ end; end
@@ -35,10 +35,40 @@ class Definition < BasicObject
35
35
  Gradient.new(*args)
36
36
  end
37
37
 
38
- def url(arg)
39
- "url(#{arg.inspect})"
38
+ def url(value)
39
+ "url(#{value.to_s.inspect})"
40
40
  end
41
41
 
42
+ %w[blur brightness rotate contrast grayscale invert opacity saturate sepia].each {|name|
43
+ define_method name do |value|
44
+ "#{name}(#{value})"
45
+ end
46
+ }
47
+
48
+ def rgb(r, g, b)
49
+ "rgb(#{r}, #{g}, #{b}, #{a})"
50
+ end
51
+
52
+ def rgba(r, g, b, a)
53
+ "rgba(#{r}, #{g}, #{b}, #{a})"
54
+ end
55
+
56
+ %w[scale skew translate].each {|name|
57
+ define_method name do |a, b = nil|
58
+ if b
59
+ "#{name}(#{a}, #{b})"
60
+ else
61
+ "#{name}(#{a})"
62
+ end
63
+ end
64
+ }
65
+
66
+ %w[translateX translateY translateZ rotateX rotateY rotateZ skewX skewY scaleX scaleY].each {|name|
67
+ define_method name do |value|
68
+ "#{name}(#{value})"
69
+ end
70
+ }
71
+
42
72
  def background(*args)
43
73
  if Gradient === args.first
44
74
  if args.length > 1
@@ -67,6 +97,15 @@ class Definition < BasicObject
67
97
 
68
98
  options.each {|name, value|
69
99
  case name
100
+ when :top, :bottom, :left, :right
101
+ if ::Hash === value
102
+ value.each {|n, v|
103
+ style "border-#{name}-#{n}", v
104
+ }
105
+ else
106
+ style "border-#{name}", value
107
+ end
108
+
70
109
  when :radius
71
110
  if ::Hash === value
72
111
  value.each {|horizontal, value|
@@ -134,14 +173,58 @@ class Definition < BasicObject
134
173
  style 'filter', "alpha(opacity=#{(value * 100).to_i})"
135
174
  end
136
175
 
176
+ def animation(*args)
177
+ if Hash === args.first
178
+ if args.length == 1
179
+ options = args.first
180
+ end
181
+
182
+ options.each {|name, value|
183
+ style "-webkit-animation-#{name}", value
184
+ style "animation-#{name}", value
185
+ }
186
+ else
187
+ style 'animation', args
188
+ style '-webkit-animation', args
189
+ end
190
+ end
191
+
192
+ def transition(*args)
193
+ style 'transition', args
194
+ style '-webkit-transition', args
195
+ style '-moz-transition', args
196
+ end
197
+
198
+ def user_select(*args)
199
+ style 'user-select', args
200
+ style '-webkit-user-select', args
201
+ style '-moz-user-select', args
202
+ style '-ms-user-select', args
203
+ end
204
+
205
+ def transform(*args)
206
+ style 'transform', args
207
+ style '-webkit-transform', args
208
+ style '-moz-transform', args
209
+ style '-ms-transform', args
210
+ style '-o-transform', args
211
+ end
212
+
213
+ def filter(*args)
214
+ style 'filter', args
215
+ style '-webkit-filter', args
216
+ style '-moz-filter', args
217
+ style '-ms-filter', args
218
+ style '-o-filter', args
219
+ end
220
+
137
221
  def method_missing(name, *args, &block)
138
- name = name.to_s
139
- important = name.end_with? ?!
140
- name = name[0 .. -2] if important
222
+ name = name.to_s
141
223
 
142
- @important = true if important
224
+ if name.end_with? ?!
225
+ name = name[0 .. -2]
143
226
 
144
- if important && respond_to?(name)
227
+ @important = true
145
228
  __send__ name, *args, &block
146
229
  @important = false
147
230
 
@@ -0,0 +1,28 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
+ #
8
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
+ #++
10
+
11
+ class Paggio; class CSS < BasicObject
12
+
13
+ class Font < BasicObject
14
+ attr_reader :name
15
+
16
+ def initialize(name)
17
+ @name = name
18
+ @definition = Definition.new
19
+
20
+ font family: name
21
+ end
22
+
23
+ def method_missing(*args, &block)
24
+ @definition.__send__(*args, &block)
25
+ end
26
+ end
27
+
28
+ end; end
@@ -0,0 +1,27 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
+ #
8
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
+ #++
10
+
11
+ class Paggio; class CSS < BasicObject
12
+
13
+ class Rule < BasicObject
14
+ attr_reader :selector, :media
15
+
16
+ def initialize(selector, media)
17
+ @selector = selector
18
+ @media = media
19
+ @definition = Definition.new
20
+ end
21
+
22
+ def method_missing(*args, &block)
23
+ @definition.__send__(*args, &block)
24
+ end
25
+ end
26
+
27
+ end; end
@@ -11,6 +11,7 @@
11
11
  class Paggio; class CSS < BasicObject
12
12
 
13
13
  class Unit
14
+ TYPES = %w[em ex ch rem vh vw vmin vmax px mm cm in pt pc s deg].map(&:to_sym)
14
15
  COMPATIBLE = %w[in pt mm cm px pc].map(&:to_sym)
15
16
 
16
17
  attr_reader :type, :number
@@ -25,6 +26,18 @@ class Unit
25
26
  end
26
27
 
27
28
  def ==(other)
29
+ unless Unit === other
30
+ unless other.respond_to? :to_u
31
+ raise TypeError, "no implicit conversion of #{other.class} into Unit"
32
+ end
33
+
34
+ other = other.to_u
35
+ end
36
+
37
+ unless Unit === other
38
+ other = Unit.new(other, @type)
39
+ end
40
+
28
41
  @number == convert(other, @type)
29
42
  end
30
43
 
@@ -38,7 +51,7 @@ class Unit
38
51
  [@number, @type].hash
39
52
  end
40
53
 
41
- %w[em ex ch rem vh vw vmin vmax px mm cm in pt pc].map(&:to_sym).each {|name|
54
+ TYPES.each {|name|
42
55
  define_method name do
43
56
  Unit.new(convert(self, name), name)
44
57
  end
@@ -113,7 +126,7 @@ class Unit
113
126
  end
114
127
 
115
128
  def to_s
116
- "#{@number}#{@type}"
129
+ "#@number#@type"
117
130
  end
118
131
 
119
132
  alias to_str to_s
@@ -152,7 +165,7 @@ end
152
165
  end; end
153
166
 
154
167
  class Numeric
155
- %w[em ex ch rem vh vw vmin vmax px mm cm in pt pc].map(&:to_sym).each {|name|
168
+ Paggio::CSS::Unit::TYPES.each {|name|
156
169
  define_method name do
157
170
  Paggio::CSS::Unit.new(self, name)
158
171
  end
data/lib/paggio/css.rb CHANGED
@@ -11,12 +11,13 @@
11
11
  require 'paggio/css/unit'
12
12
  require 'paggio/css/color'
13
13
  require 'paggio/css/definition'
14
+ require 'paggio/css/rule'
15
+ require 'paggio/css/font'
16
+ require 'paggio/css/animation'
14
17
 
15
18
  class Paggio
16
19
 
17
20
  class CSS < BasicObject
18
- Rule = ::Struct.new(:selector, :definition)
19
-
20
21
  def self.selector(list)
21
22
  result = ''
22
23
 
@@ -35,20 +36,29 @@ class CSS < BasicObject
35
36
  end
36
37
  end
37
38
 
38
- attr_reader :rules
39
+ attr_reader :rules, :media, :fonts, :animations
39
40
 
40
- def initialize(&block)
41
+ def initialize(defer: false, &block)
41
42
  ::Kernel.raise ::ArgumentError, 'no block given' unless block
42
43
 
43
- @selector = []
44
- @current = []
45
- @rules = []
44
+ @selector = []
45
+ @current = []
46
+ @rules = []
47
+ @fonts = []
48
+ @animations = []
49
+
50
+ @block = block
51
+
52
+ build! unless defer
53
+ end
46
54
 
47
- if block.arity == 0
48
- instance_exec(&block)
55
+ def build!(force_call: false)
56
+ if !force_call && @block.arity == 0
57
+ instance_exec(&@block)
49
58
  else
50
- block.call(self)
59
+ @block.call(self)
51
60
  end
61
+ @block = nil
52
62
  end
53
63
 
54
64
  def rule(*names, &block)
@@ -60,19 +70,49 @@ class CSS < BasicObject
60
70
 
61
71
  names.each {|name|
62
72
  @selector << name
63
- @current << Rule.new(CSS.selector(@selector), Definition.new)
73
+ @current << Rule.new(CSS.selector(@selector), @media)
64
74
 
65
- block.call(self)
75
+ block.call
66
76
 
67
77
  @selector.pop
68
78
  @rules << @current.pop
69
79
  }
70
80
  end
71
81
 
82
+ def media(query, *args, &block)
83
+ if block
84
+ old, @media = @media, query
85
+ block.call
86
+ @media = old
87
+ else
88
+ method_missing(:media, query, *args)
89
+ end
90
+ end
91
+
92
+ def font(name, *args, &block)
93
+ if block
94
+ @current << Font.new(name)
95
+ block.call
96
+ @fonts << @current.pop
97
+ else
98
+ method_missing(:font, name, *args)
99
+ end
100
+ end
101
+
102
+ def animation(name, *args, &block)
103
+ if block
104
+ @current << Animation.new(name)
105
+ block.call
106
+ @animations << @current.pop
107
+ else
108
+ method_missing(:animation, name, *args)
109
+ end
110
+ end
111
+
72
112
  # this is needed because the methods inside the rule blocks are actually
73
113
  # called on the CSS object
74
- def method_missing(name, *args, &block)
75
- @current.last.definition.__send__(name, *args, &block)
114
+ def method_missing(*args, &block)
115
+ @current.last.__send__(*args, &block)
76
116
  end
77
117
  end
78
118
 
@@ -78,11 +78,21 @@ class Formatter
78
78
 
79
79
  def indent(&block)
80
80
  if indent?
81
- @options[:indent][:level] += 1
82
- block.call
83
- @options[:indent][:level] -= 1
81
+ if block
82
+ @options[:indent][:level] += 1
83
+ block.call
84
+ @options[:indent][:level] -= 1
85
+ else
86
+ @options[:indent][:level] += 1
87
+ end
84
88
  else
85
- block.call
89
+ block.call if block
90
+ end
91
+ end
92
+
93
+ def deindent
94
+ if indent?
95
+ @options[:indent][:level] -= 1
86
96
  end
87
97
  end
88
98
 
@@ -140,6 +150,11 @@ Formatter.for HTML::Element do |f, item|
140
150
  f.print "<#{name} #{attrs.join(' ')}>"
141
151
  end
142
152
 
153
+ next if %w[
154
+ area base br col embed hr img input keygen link
155
+ menuitem meta param source track wbr
156
+ ].include?(name.to_s.downcase)
157
+
143
158
  f.indent {
144
159
  if inner = item.instance_eval { @inner_html }
145
160
  f.print inner
@@ -166,17 +181,55 @@ Formatter.for HTML::Element do |f, item|
166
181
  f.print "</#{name}>"
167
182
  end
168
183
 
184
+ Formatter.for CSS::Definition::Style do |f, style|
185
+ f.print "#{style.name}: #{style.value}#{' !important' if style.important};"
186
+ end
187
+
169
188
  Formatter.for CSS do |f, item|
189
+ item.fonts.each {|font|
190
+ f.print '@font-face {'
191
+ f.indent {
192
+ font.each {|style|
193
+ f.format style
194
+ }
195
+ }
196
+ f.print '}'
197
+ }
198
+
199
+ item.animations.each {|animation|
200
+ ['', '-webkit-', '-moz-', '-o-'].each {|platform|
201
+ f.print "@#{platform}keyframes #{animation.name} {"
202
+ animation.steps.each {|step|
203
+ f.print "#{step.value} {"
204
+ step.each {|style|
205
+ f.format style
206
+ }
207
+ f.print '}'
208
+ }
209
+ f.print '}'
210
+ }
211
+ }
212
+
170
213
  item.rules.reverse.each {|rule|
171
- next if rule.definition.empty?
214
+ next if rule.empty?
215
+
216
+ if m = rule.media
217
+ f.print "@media #{m} {"
218
+ f.indent
219
+ end
172
220
 
173
221
  f.print "#{rule.selector} {"
174
222
  f.indent {
175
- rule.definition.each {|style|
176
- f.print "#{style.name}: #{style.value}#{' !important' if style.important};"
223
+ rule.each {|style|
224
+ f.format style
177
225
  }
178
226
  }
179
227
  f.print '}'
228
+
229
+ if rule.media
230
+ f.print '}'
231
+ f.deindent
232
+ end
180
233
  }
181
234
  end
182
235
 
@@ -27,7 +27,7 @@ class A < self
27
27
  media: :media,
28
28
  }.each {|name, attribute|
29
29
  defhelper name do |value|
30
- @attributes[attribute] = value.to_s
30
+ @attributes[name] = value.to_s
31
31
  end
32
32
  }
33
33
 
@@ -17,7 +17,7 @@ class Base < self
17
17
  target: :target,
18
18
  }.each {|name, attribute|
19
19
  defhelper name do |value|
20
- @attributes[attribute] = value.to_s
20
+ @attributes[name] = value.to_s
21
21
  end
22
22
  }
23
23
  end
@@ -22,7 +22,7 @@ class Button < self
22
22
  target: :formtarget,
23
23
  }.each {|name, attributes|
24
24
  defhelper name do |value|
25
- @attributes[attribute] = value.to_s
25
+ @attributes[name] = value.to_s
26
26
  end
27
27
  }
28
28
 
@@ -15,7 +15,7 @@ class Canvas < self
15
15
  height: :height
16
16
  }.each {|name, attribute|
17
17
  defhelper name do |value|
18
- @attributes[attribute] = value.to_s
18
+ @attributes[name] = value.to_s
19
19
  end
20
20
  }
21
21
  end
@@ -0,0 +1,24 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
+ #
8
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
+ #++
10
+
11
+ class Paggio; class HTML < BasicObject; class Element < BasicObject
12
+
13
+ class Embed < self
14
+ { type: :type,
15
+ height: :height,
16
+ width: :width
17
+ }.each {|name, attribute|
18
+ defhelper name do |value|
19
+ @attributes[name] = value
20
+ end
21
+ }
22
+ end
23
+
24
+ end; end; end
@@ -23,7 +23,7 @@ class Img < self
23
23
  map: :usemap,
24
24
  }.each {|name, attribute|
25
25
  defhelper name do |value|
26
- @attributes[attribute] = value.to_s
26
+ @attributes[name] = value.to_s
27
27
  end
28
28
  }
29
29
 
@@ -18,9 +18,10 @@ class Input < self
18
18
  place_holder: :placeholder,
19
19
  read_only: :readonly,
20
20
  required: :required,
21
+ limit: :maxlength
21
22
  }.each {|name, attribute|
22
23
  defhelper name do |value|
23
- @attributes[attribute] = value
24
+ @attributes[name] = value
24
25
  end
25
26
  }
26
27
  end
@@ -0,0 +1,20 @@
1
+ class Paggio; class HTML < BasicObject; class Element < BasicObject
2
+
3
+ class Link < self
4
+ { cross_origin: :crossorigin,
5
+
6
+ href: :href,
7
+ href_lang: :hreflang,
8
+
9
+ media: :media,
10
+ rel: :rel,
11
+ sizes: :sizes,
12
+ type: :type,
13
+ }.each {|name, attribute|
14
+ defhelper name do |value|
15
+ @attributes[name] = value.to_s
16
+ end
17
+ }
18
+ end
19
+
20
+ end; end; end
@@ -0,0 +1,27 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
+ #
8
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
+ #++
10
+
11
+ class Paggio; class HTML < BasicObject; class Element < BasicObject
12
+
13
+ class Object < self
14
+ { type: :type,
15
+ data: :data,
16
+ name: :name,
17
+
18
+ height: :height,
19
+ width: :width
20
+ }.each {|name, attribute|
21
+ defhelper name do |value|
22
+ @attributes[name] = value
23
+ end
24
+ }
25
+ end
26
+
27
+ end; end; end
@@ -0,0 +1,24 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
+ #
8
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
+ #++
10
+
11
+ class Paggio; class HTML < BasicObject; class Element < BasicObject
12
+
13
+ class Optgroup < self
14
+ %w[label value].each {|name|
15
+ defhelper name do |value|
16
+ @attributes[name] = value
17
+ end
18
+ }
19
+
20
+ defhelper! :disabled
21
+ defhelper! :selected
22
+ end
23
+
24
+ end; end; end
@@ -0,0 +1,24 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
+ #
8
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
+ #++
10
+
11
+ class Paggio; class HTML < BasicObject; class Element < BasicObject
12
+
13
+ class Option < self
14
+ %w[label value].each {|name|
15
+ defhelper name do |value|
16
+ @attributes[name] = value
17
+ end
18
+ }
19
+
20
+ defhelper! :disabled
21
+ defhelper! :selected
22
+ end
23
+
24
+ end; end; end
@@ -0,0 +1,25 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
+ #
8
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
+ #++
10
+
11
+ class Paggio; class HTML < BasicObject; class Element < BasicObject
12
+
13
+ class Select < self
14
+ %w[form name size].each {|name|
15
+ defhelper name do |value|
16
+ @attributes[name] = value
17
+ end
18
+ }
19
+
20
+ defhelper! :auto_focus, :autofocus
21
+ defhelper! :disabled
22
+ defhelper! :required
23
+ end
24
+
25
+ end; end; end
@@ -13,8 +13,14 @@ require 'paggio/html/element/base'
13
13
  require 'paggio/html/element/blockquote'
14
14
  require 'paggio/html/element/button'
15
15
  require 'paggio/html/element/canvas'
16
+ require 'paggio/html/element/embed'
16
17
  require 'paggio/html/element/img'
17
18
  require 'paggio/html/element/input'
19
+ require 'paggio/html/element/link'
20
+ require 'paggio/html/element/object'
21
+ require 'paggio/html/element/option'
22
+ require 'paggio/html/element/optgroup'
23
+ require 'paggio/html/element/select'
18
24
  require 'paggio/html/element/td'
19
25
 
20
26
  class Paggio; class HTML < BasicObject
@@ -25,7 +31,7 @@ class Element < BasicObject
25
31
 
26
32
  const = name.capitalize
27
33
 
28
- if const_defined?(const)
34
+ if !const.to_s.include?('-') && const_defined?(const)
29
35
  const_get(const).new(owner, name, attributes)
30
36
  else
31
37
  super
@@ -51,15 +57,20 @@ class Element < BasicObject
51
57
  end
52
58
 
53
59
  def method_missing(name, content = nil, &block)
54
- if content
55
- self << ::Paggio::Utils.heredoc(content.to_s)
56
- end
57
-
58
60
  if name.to_s.end_with? ?!
59
61
  @attributes[:id] = name[0 .. -2]
60
62
  else
61
- @last = name
62
- @class_names.push(name)
63
+ @class_names << name
64
+ end
65
+
66
+ if ::Hash === content
67
+ if content.has_key?(:class) || content.has_key?(:classes)
68
+ @class_names.unshift(*(content.delete(:class).to_s.split | content.delete(:classes).to_a))
69
+ end
70
+
71
+ ::Paggio::Utils.deep_merge!(@attributes, content)
72
+ elsif content
73
+ self >> content
63
74
  end
64
75
 
65
76
  @owner.extend!(self, &block) if block
@@ -68,10 +79,9 @@ class Element < BasicObject
68
79
  end
69
80
 
70
81
  def [](*names)
71
- return unless @last
72
-
73
- @class_names.pop
74
- @class_names.push([@last, *names].join('-'))
82
+ if last = @class_names.pop
83
+ @class_names << [last, *names].join('-')
84
+ end
75
85
 
76
86
  self
77
87
  end
@@ -82,6 +92,23 @@ class Element < BasicObject
82
92
  self
83
93
  end
84
94
 
95
+ def >>(content)
96
+ self << ::Paggio::Utils.heredoc(content.to_s)
97
+ self
98
+ end
99
+
100
+ defhelper :style do |hash|
101
+ @attributes[:style] = hash.map {|name, value|
102
+ "#{name}: #{value}"
103
+ }.join(';')
104
+ end
105
+
106
+ defhelper :data do |hash|
107
+ hash.each {|name, value|
108
+ @attributes["data-#{name}"] = value.to_s
109
+ }
110
+ end
111
+
85
112
  def inspect
86
113
  if @children.empty?
87
114
  "#<HTML::Element(#{@name.upcase})>"
data/lib/paggio/html.rb CHANGED
@@ -8,7 +8,6 @@
8
8
  # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
9
  #++
10
10
 
11
-
12
11
  require 'paggio/html/helpers'
13
12
  require 'paggio/html/element'
14
13
 
@@ -17,24 +16,31 @@ class Paggio
17
16
  class HTML < BasicObject
18
17
  attr_reader :version
19
18
 
20
- def initialize(version = 5, &block)
19
+ def initialize(version = 5, defer: false, &block)
21
20
  ::Kernel.raise ::ArgumentError, 'no block given' unless block
22
21
 
23
22
  @version = version
24
23
  @roots = []
25
24
  @current = nil
26
25
 
27
- if block.arity == 0
28
- instance_exec(&block)
29
- else
30
- block.call(self)
31
- end
26
+ @block = block
27
+
28
+ build! unless defer
32
29
  end
33
30
 
34
31
  def <<(what)
35
32
  (@current || @roots) << what
36
33
  end
37
34
 
35
+ def build!(force_call: false)
36
+ if !force_call && @block.arity == 0
37
+ instance_exec(&@block)
38
+ else
39
+ @block.call(self)
40
+ end
41
+ @block = nil
42
+ end
43
+
38
44
  def root!
39
45
  @roots.first
40
46
  end
@@ -65,6 +71,11 @@ class HTML < BasicObject
65
71
  @roots.each(&block)
66
72
  end
67
73
 
74
+ def text(*fragments, &block)
75
+ fragments << yield if block
76
+ fragments.each { |fragment| self << fragment }
77
+ end
78
+
68
79
  def method_missing(name, *args, &block)
69
80
  if name.to_s.end_with? ?!
70
81
  return super
@@ -93,6 +104,9 @@ class HTML < BasicObject
93
104
  element
94
105
  end
95
106
 
107
+ # Support for custom elements
108
+ alias e method_missing
109
+
96
110
  def inspect
97
111
  if @roots.empty?
98
112
  "#<HTML(#@version)>"
data/paggio.gemspec CHANGED
@@ -1,11 +1,12 @@
1
1
  Gem::Specification.new {|s|
2
- s.name = 'paggio'
3
- s.version = '0.2.3'
4
- s.author = 'meh.'
5
- s.email = 'meh@schizofreni.co'
6
- s.homepage = 'http://github.com/meh/paggio'
7
- s.platform = Gem::Platform::RUBY
8
- s.summary = 'Ruby, HTML and CSS at war.'
2
+ s.name = 'paggio'
3
+ s.version = '0.3.0'
4
+ s.author = 'meh.'
5
+ s.email = 'meh@schizofreni.co'
6
+ s.homepage = 'http://github.com/opal/paggio'
7
+ s.platform = Gem::Platform::RUBY
8
+ s.summary = 'Ruby, HTML and CSS at war.'
9
+ s.license = 'WTFPL'
9
10
 
10
11
  s.files = `git ls-files`.split("\n")
11
12
  s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
data/spec/css_spec.rb CHANGED
@@ -8,7 +8,7 @@ describe Paggio::CSS do
8
8
  end
9
9
  end
10
10
 
11
- css.to_s.should == "#lol {\n\tcolor: black;\n}\n"
11
+ expect(css.to_s).to eq("#lol {\n\tcolor: black;\n}\n")
12
12
  end
13
13
 
14
14
  it 'builds border-radius correctly' do
@@ -18,7 +18,7 @@ describe Paggio::CSS do
18
18
  end
19
19
  end
20
20
 
21
- css.to_s.should == "#lol {\n\t-moz-border-radius: 5px;\n\t-webkit-border-radius: 5px;\n\tborder-radius: 5px;\n}\n"
21
+ expect(css.to_s).to eq("#lol {\n\t-moz-border-radius: 5px;\n\t-webkit-border-radius: 5px;\n\tborder-radius: 5px;\n}\n")
22
22
 
23
23
  css = Paggio.css do
24
24
  rule '#lol' do
@@ -26,7 +26,7 @@ describe Paggio::CSS do
26
26
  end
27
27
  end
28
28
 
29
- css.to_s.should == "#lol {\n\t-moz-border-radius-topleft: 5px;\n\t-webkit-border-top-left-radius: 5px;\n\tborder-top-left-radius: 5px;\n}\n"
29
+ expect(css.to_s).to eq("#lol {\n\t-moz-border-radius-topleft: 5px;\n\t-webkit-border-top-left-radius: 5px;\n\tborder-top-left-radius: 5px;\n}\n")
30
30
  end
31
31
 
32
32
  it 'builds box-shadow correctly' do
@@ -36,6 +36,20 @@ describe Paggio::CSS do
36
36
  end
37
37
  end
38
38
 
39
- css.to_s.should == "#lol {\n\t-moz-box-shadow: 0 0 5px black;\n\t-webkit-box-shadow: 0 0 5px black;\n\tbox-shadow: 0 0 5px black;\n}\n"
39
+ expect(css.to_s).to eq("#lol {\n\t-moz-box-shadow: 0 0 5px black;\n\t-webkit-box-shadow: 0 0 5px black;\n\tbox-shadow: 0 0 5px black;\n}\n")
40
+ end
41
+
42
+ it 'builds @font-face' do
43
+ css = Paggio.css do
44
+ font 'hue' do
45
+ src url('test')
46
+ end
47
+ end
48
+
49
+ expect(css.to_s).to eq("@font-face {\n\tfont-family: hue;\n\tsrc: url(\"test\");\n}\n")
50
+ end
51
+
52
+ it 'builds @keyframes' do
53
+
40
54
  end
41
55
  end
data/spec/html_spec.rb ADDED
@@ -0,0 +1,185 @@
1
+ require 'paggio'
2
+
3
+ describe Paggio::HTML do
4
+ it 'builds an element' do
5
+ html = Paggio.html! do
6
+ div
7
+ end
8
+
9
+ expect(html.to_s).to eq("<div>\n</div>\n")
10
+ end
11
+
12
+ it 'builds an element with text content' do
13
+ html = Paggio.html! do
14
+ div "foo bar"
15
+ end
16
+
17
+ expect(html.to_s).to eq("<div>\n\tfoo bar\n</div>\n")
18
+
19
+ html = Paggio.html! do
20
+ div do
21
+ "foo bar"
22
+ end
23
+ end
24
+
25
+ expect(html.to_s).to eq("<div>\n\tfoo bar\n</div>\n")
26
+ end
27
+
28
+ it 'builds an element with attributes' do
29
+ html = Paggio.html! do
30
+ div class: :wut
31
+ end
32
+
33
+ expect(html.to_s).to eq("<div class=\"wut\">\n</div>\n")
34
+ end
35
+
36
+ it 'builds deeper trees' do
37
+ html = Paggio.html! do
38
+ div do
39
+ span do
40
+ "wut"
41
+ end
42
+ end
43
+ end
44
+
45
+ expect(html.to_s).to eq("<div>\n\t<span>\n\t\twut\n\t</span>\n</div>\n")
46
+ end
47
+
48
+ it 'sets classes with methods' do
49
+ html = Paggio.html! do
50
+ div.nice.element
51
+ end
52
+
53
+ expect(html.to_s).to eq("<div class=\"nice element\">\n</div>\n")
54
+ end
55
+
56
+ it 'nests when setting classes' do
57
+ html = Paggio.html! do
58
+ div.nice.element do
59
+ span.nicer 'lol'
60
+ end
61
+ end
62
+
63
+ expect(html.to_s).to eq("<div class=\"nice element\">\n\t<span class=\"nicer\">\n\t\tlol\n\t</span>\n</div>\n")
64
+ end
65
+
66
+ it 'joins class name properly' do
67
+ html = Paggio.html! do
68
+ i.icon[:legal]
69
+ end
70
+
71
+ expect(html.to_s).to eq("<i class=\"icon-legal\">\n</i>\n")
72
+
73
+ html = Paggio.html! do
74
+ i.icon.icon[:legal, :shmegal]
75
+ end
76
+
77
+ expect(html.to_s).to eq("<i class=\"icon icon-legal-shmegal\">\n</i>\n")
78
+ end
79
+
80
+ it 'sets the id' do
81
+ html = Paggio.html! do
82
+ div.omg!
83
+ end
84
+
85
+ expect(html.to_s).to eq("<div id=\"omg\">\n</div>\n")
86
+ end
87
+
88
+ it 'chains ids and classes' do
89
+ html = Paggio.html! do
90
+ div.omg!.wut
91
+ end
92
+
93
+ expect(html.to_s).to eq("<div id=\"omg\" class=\"wut\">\n</div>\n")
94
+ end
95
+
96
+ it 'chains ids and attributes' do
97
+ html = Paggio.html! do
98
+ div.omg! class: :wut
99
+ end
100
+
101
+ expect(html.to_s).to eq("<div id=\"omg\" class=\"wut\">\n</div>\n")
102
+ end
103
+
104
+ it 'chains classes and attributes' do
105
+ html = Paggio.html! do
106
+ div.wut width: 80
107
+ end
108
+
109
+ expect(html.to_s).to eq("<div width=\"80\" class=\"wut\">\n</div>\n")
110
+ end
111
+
112
+ it 'overrides with id from attributes' do
113
+ html = Paggio.html! do
114
+ div.omg! id: 'ikr'
115
+ end
116
+
117
+ expect(html.to_s).to eq("<div id=\"ikr\">\n</div>\n")
118
+ expect(html.to_s).not_to eq("<div id=\"omg\">\n</div>\n")
119
+ end
120
+
121
+ it 'coalesces classes from attributes' do
122
+ html = Paggio.html! do
123
+ div.wut class: 'rofl'
124
+ end
125
+
126
+ expect(html.to_s).to eq("<div class=\"rofl wut\">\n</div>\n")
127
+ expect(html.to_s).not_to eq("<div class=\"wut\" class=\"rofl\">n")
128
+
129
+ html = Paggio.html! do
130
+ div.wut class: 'rofl idk'
131
+ end
132
+
133
+ expect(html.to_s).to eq("<div class=\"rofl idk wut\">\n</div>\n")
134
+ expect(html.to_s).not_to eq("<div class=\"wut\" class=\"rofl idk\">n")
135
+ end
136
+
137
+ it 'coalesces multiple classes from attributes' do
138
+ html = Paggio.html! do
139
+ div.wut classes: %w[rofl idk]
140
+ end
141
+
142
+ expect(html.to_s).to eq("<div class=\"rofl idk wut\">\n</div>\n")
143
+ expect(html.to_s).not_to eq("<div class=\"wut\" classes=\"[&quot;rofl&quot;, &quot;idk&quot;]\">\n</div>\n")
144
+ end
145
+
146
+ it 'joins class name properly with class attributes' do
147
+ html = Paggio.html! do
148
+ i.icon(class: 'illegal')[:legal]
149
+ end
150
+
151
+ expect(html.to_s).to eq("<i class=\"illegal icon-legal\">\n</i>\n")
152
+ end
153
+
154
+ it 'allows for defered build' do
155
+ html = Paggio::HTML.new(defer: true) do
156
+ div
157
+ end
158
+ expect(html.roots!.length).to eq(0)
159
+
160
+ html.build!
161
+ expect(html.roots!.length).to eq(1)
162
+ end
163
+
164
+ it 'allows for custom elements' do
165
+ html = Paggio.html! do
166
+ e('custom-element').test.test!
167
+ end
168
+
169
+ expect(html.to_s).to eq("<custom-element id=\"test\" class=\"test\">\n</custom-element>\n")
170
+ end
171
+
172
+ it 'supports text nodes' do
173
+ html = Paggio.html! do
174
+ div {
175
+ text "test"
176
+ text { "test" }
177
+ text "test"
178
+ div
179
+ text "test"
180
+ }
181
+ end
182
+
183
+ expect(html.to_s).to eq("<div>\n\ttest\n\ttest\n\ttest\n\t<div>\n\t</div>\n\ttest\n</div>\n")
184
+ end
185
+ end
metadata CHANGED
@@ -1,28 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paggio
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - meh.
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-02 00:00:00.000000000 Z
11
+ date: 2021-11-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description:
13
+ description:
14
14
  email: meh@schizofreni.co
15
15
  executables: []
16
16
  extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
+ - ".github/workflows/build.yml"
20
+ - ".rspec"
19
21
  - ".travis.yml"
22
+ - Gemfile
23
+ - Gemfile.lock
20
24
  - README.md
21
25
  - Rakefile
22
26
  - lib/paggio.rb
23
27
  - lib/paggio/css.rb
28
+ - lib/paggio/css/animation.rb
24
29
  - lib/paggio/css/color.rb
25
30
  - lib/paggio/css/definition.rb
31
+ - lib/paggio/css/font.rb
32
+ - lib/paggio/css/rule.rb
26
33
  - lib/paggio/css/unit.rb
27
34
  - lib/paggio/formatter.rb
28
35
  - lib/paggio/html.rb
@@ -32,8 +39,14 @@ files:
32
39
  - lib/paggio/html/element/blockquote.rb
33
40
  - lib/paggio/html/element/button.rb
34
41
  - lib/paggio/html/element/canvas.rb
42
+ - lib/paggio/html/element/embed.rb
35
43
  - lib/paggio/html/element/img.rb
36
44
  - lib/paggio/html/element/input.rb
45
+ - lib/paggio/html/element/link.rb
46
+ - lib/paggio/html/element/object.rb
47
+ - lib/paggio/html/element/optgroup.rb
48
+ - lib/paggio/html/element/option.rb
49
+ - lib/paggio/html/element/select.rb
37
50
  - lib/paggio/html/element/td.rb
38
51
  - lib/paggio/html/helpers.rb
39
52
  - lib/paggio/markdown.rb
@@ -42,10 +55,12 @@ files:
42
55
  - lib/paggio/utils.rb
43
56
  - paggio.gemspec
44
57
  - spec/css_spec.rb
45
- homepage: http://github.com/meh/paggio
46
- licenses: []
58
+ - spec/html_spec.rb
59
+ homepage: http://github.com/opal/paggio
60
+ licenses:
61
+ - WTFPL
47
62
  metadata: {}
48
- post_install_message:
63
+ post_install_message:
49
64
  rdoc_options: []
50
65
  require_paths:
51
66
  - lib
@@ -60,10 +75,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
75
  - !ruby/object:Gem::Version
61
76
  version: '0'
62
77
  requirements: []
63
- rubyforge_project:
64
- rubygems_version: 2.1.5
65
- signing_key:
78
+ rubygems_version: 3.2.22
79
+ signing_key:
66
80
  specification_version: 4
67
81
  summary: Ruby, HTML and CSS at war.
68
82
  test_files:
69
83
  - spec/css_spec.rb
84
+ - spec/html_spec.rb