css 0.0.3 → 0.0.4

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.
data/lib/css.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  require "numbers"
2
+ require "monkey_patches"
2
3
  require "css/colors"
3
4
  require "css/errors"
4
- require "css/normalize"
5
5
  require "css/parser"
6
6
  require "css/property"
7
7
  require "css/rule"
8
8
  require "css/rule_set"
9
9
 
10
10
  module CSS
11
- VERSION = "0.0.3"
11
+ VERSION = "0.0.4"
12
12
  end
@@ -0,0 +1,16 @@
1
+ module CSS
2
+ module Normalize
3
+ def normalize_property_name(name)
4
+ name = name.to_s.strip
5
+ if name =~ /[A-Z]/
6
+ name.gsub(/([A-Z])/) do |match|
7
+ "-#{match.downcase}"
8
+ end
9
+ elsif name =~ /_/
10
+ name.gsub(/_/, '-')
11
+ else
12
+ name
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ module CSS
2
+ module Orientation
3
+ NESW = %w(top right bottom left)
4
+
5
+ def compact_orientation(top, right, bottom, left)
6
+ if top && right && bottom && left
7
+ if [top, right, bottom, left] == Array.new(4) { top }
8
+ top.value
9
+ elsif [top, bottom] == Array.new(2) { top } && [left, right] == Array.new(2) { left }
10
+ [top, left].map { |s| s.value }.join(' ')
11
+ elsif [top, bottom] != Array.new(2) { top } && [left, right] == Array.new(2) { left }
12
+ [top, left, bottom].map { |s| s.value }.join(' ')
13
+ else
14
+ [top, right, bottom, left].map { |s| s.value }.join(' ')
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -4,19 +4,17 @@ module CSS
4
4
  'background'
5
5
  end
6
6
 
7
- def to_s
8
- %w(color image repeat position attachment).map { |prop| @properties[prop] && @properties[prop] != default_properties[prop] ? @properties[prop].value : nil }.compact.join(' ')
9
- end
10
-
11
7
  def to_style
12
- [name, to_s].join(':')
8
+ values = %w(color image repeat position attachment).map { |prop| @properties[prop] && @properties[prop] != default_properties[prop] ? @properties[prop].value : nil }.compact.join(' ')
9
+ [name, values].join(':')
13
10
  end
14
11
 
15
12
  private
16
- def init(name, value)
13
+ def init(parent, name, value)
14
+ @parent = parent
17
15
  if name =~ /-/
18
16
  property_name = name.sub(/[^-]+-(.*)/, '\1')
19
- @properties[property_name] = Property.new(:p, property_name, value)
17
+ @properties[property_name] = Property.new(self, property_name, value)
20
18
  else
21
19
  expand_property value if value
22
20
  end
@@ -24,11 +22,11 @@ module CSS
24
22
 
25
23
  def default_properties
26
24
  @@default_properties ||= {
27
- 'color' => Property.create('color', 'transparent'),
28
- 'image' => Property.create('image', 'none'),
29
- 'repeat' => Property.create('repeat', 'repeat'),
30
- 'position' => Property.create('position', 'top left'),
31
- 'attachment' => Property.create('attachment', 'scroll')
25
+ 'color' => Property.new(self, 'color', 'transparent'),
26
+ 'image' => Property.new(self, 'image', 'none'),
27
+ 'repeat' => Property.new(self, 'repeat', 'repeat'),
28
+ 'position' => Property.new(self, 'position', 'top left'),
29
+ 'attachment' => Property.new(self, 'attachment', 'scroll')
32
30
  }
33
31
  end
34
32
 
@@ -37,22 +35,22 @@ module CSS
37
35
  while values.size > 0
38
36
  val = values.shift
39
37
  if val =~ /^(#|rgb)/ || val == 'transparent' || Colors::NAMES.keys.include?(val.to_s.upcase)
40
- @properties['color'] = Property.create('color', val)
38
+ @properties['color'] = Property.new(self, 'color', val)
41
39
  elsif val =~ /^url/
42
- @properties['image'] = Property.create('image', val)
40
+ @properties['image'] = Property.new(self, 'image', val)
43
41
  elsif val =~ /repeat/
44
- @properties['repeat'] = Property.create('repeat', val)
42
+ @properties['repeat'] = Property.new(self, 'repeat', val)
45
43
  elsif val =~ /^(\d|top|bottom|center)/
46
44
  val2 = values.shift
47
- @properties['position'] = Property.create('position', [val, val2].join(' '))
45
+ @properties['position'] = Property.new(self, 'position', [val, val2].join(' '))
48
46
  elsif val =~ /inherit/
49
47
  if values.size == 0
50
- @properties['attachment'] = Property.create('attachment', val)
48
+ @properties['attachment'] = Property.new(self, 'attachment', val)
51
49
  else
52
- @properties['repeat'] = Property.create('repeat', val)
50
+ @properties['repeat'] = Property.new(self, 'repeat', val)
53
51
  end
54
52
  elsif values.size == 0
55
- @properties['attachment'] = Property.create('attachment', val)
53
+ @properties['attachment'] = Property.new(self, 'attachment', val)
56
54
  end
57
55
  end
58
56
  end
@@ -0,0 +1,53 @@
1
+ module CSS
2
+ class BorderOrientationProperty < Property
3
+ def to_style
4
+ value = %w(size style color).map { |prop| @properties[prop] && @properties[prop] != default_properties[prop] ? @properties[prop].value : nil }.compact.join(' ')
5
+ if @properties['color'].nil? && @properties['style'].nil?
6
+ "border-size:#{@properties['size']}"
7
+ else
8
+ [name, value].join(':')
9
+ end
10
+ end
11
+
12
+ private
13
+ def init(parent, name, value)
14
+ @parent = parent
15
+ @name = name
16
+ if name =~ /-/
17
+ property_name = name.sub(/[^-]+-(.*)/, '\1')
18
+ @properties[property_name] = Property.new(self, property_name, value)
19
+ else
20
+ expand_property value if value
21
+ end
22
+ end
23
+
24
+ def default_properties
25
+ @@default_properties ||= {
26
+ 'size' => Property.new(self, 'size', '3px'),
27
+ 'style' => nil,
28
+ 'color' => Property.new(self, 'color', 'black')
29
+ }
30
+ end
31
+
32
+ def expand_property(value)
33
+ values = value.delete(';').split(/\s+/)
34
+
35
+ val = values.pop
36
+ if val =~ /^(#|rgb)/ || Colors::NAMES.include?(val.upcase)
37
+ @properties["color"] = Property.new(self, 'color', val)
38
+ else
39
+ values << val
40
+ end
41
+
42
+ val = values.pop
43
+ if val =~ /^\d/
44
+ values << val
45
+ else
46
+ @properties["style"] = Property.new(self, 'style', val) if val
47
+ end
48
+
49
+ val = values.pop
50
+ @properties["size"] = Property.new(self, 'size', val) if val
51
+ end
52
+ end
53
+ end
@@ -1,32 +1,89 @@
1
+ require 'css/helpers/orientation'
2
+
1
3
  module CSS
2
4
  class BorderProperty < Property
5
+ include Orientation
6
+
3
7
  def name
4
8
  'border'
5
9
  end
6
10
 
7
- def to_s
8
- value = %w(size style color).map { |prop| @properties[prop] && @properties[prop] != default_properties[prop] ? @properties[prop].value : nil }.compact.join(' ')
9
- if value == @properties['size'].value
10
- "#{@properties['size']}"
11
+ def to_style
12
+ sides = NESW.map { |o| @properties[o] }
13
+ value = nil
14
+ if %w(size style color).all? { |p| sides.all? { |side| @properties['top'].try(p) == side.try(p) && !side.try(p).nil? } }
15
+ value = %w(size style color).map { |p| top.send(p).value }.join(' ')
16
+ elsif %w(style color).all? { |p| sides.all? { |side| @properties['top'].try(p) == side.try(p) && !side.try(p).nil? } }
17
+ value = %w(style color).map { |p| top.send(p).value }.join(' ')
18
+ elsif %w(size style).all? { |p| sides.all? { |side| @properties['top'].try(p) == side.try(p) && !side.try(p).nil? } }
19
+ value = %w(size style).map { |p| top.send(p).value }.join(' ')
20
+ end
21
+ if value
22
+ [name, value].join(':')
11
23
  else
12
- value
24
+ if %w(style color).all? { |p| sides.all? { |side| side.try(p).nil? } } && sides.all? { |side| @properties['top'].try('size') == side.try('size') && !side.try('size').nil? }
25
+ "border-size:#{top.size.value}"
26
+ else
27
+ sides.map { |side| side.empty? ? nil : side.to_style }.compact.join(';')
28
+ end
13
29
  end
14
30
  end
15
31
 
16
- def to_style
17
- value = %w(size style color).map { |prop| @properties[prop] && @properties[prop] != default_properties[prop] ? @properties[prop].value : nil }.compact.join(' ')
18
- if value == @properties['size'].value
19
- "border-size:#{@properties['size']}"
32
+ def size
33
+ method_missing(:size)
34
+ end
35
+
36
+ def method_missing(method_name, *args)
37
+ if method_name.to_s[-1..-1] == '='
38
+ property_name = normalize_property_name(method_name.to_s.chop)
39
+ if %w(size style color).include?(property_name)
40
+ NESW.each do |o|
41
+ @properties[o].send(method_name, *args)
42
+ end
43
+ else
44
+ super
45
+ end
20
46
  else
21
- [name, value].join(':')
47
+ if %w(color size style).include?(method_name.to_s)
48
+ property = BorderUnitProperty.new(self, method_name.to_s)
49
+ is_nil = true
50
+ NESW.each do |o|
51
+ prop = @properties[o].send(method_name).try(:value)
52
+ if prop
53
+ property.send("#{o}=", prop)
54
+ is_nil = false
55
+ end
56
+ end
57
+ is_nil ? nil :property
58
+ else
59
+ super
60
+ end
22
61
  end
23
62
  end
24
63
 
64
+ def respond_to?(method_name, include_private = false)
65
+ property_name = normalize_property_name(method_name.to_s[-1..-1] == '=' ? method_name.to_s.chop : method_name)
66
+ %w(size style color).include?(property_name) || super
67
+ end
68
+
25
69
  private
26
- def init(name, value)
70
+ def init(parent, name, value)
71
+ @parent = parent
72
+
73
+ #Allocate new orientation properties
74
+ NESW.each do |o|
75
+ @properties[o] = BorderOrientationProperty.new(self, o)
76
+ end
77
+
27
78
  if name =~ /-/
28
79
  property_name = name.sub(/[^-]+-(.*)/, '\1')
29
- @properties[property_name] = Property.new(:p, property_name, value)
80
+ if NESW.include?(property_name)
81
+ @properties[property_name] = BorderOrientationProperty.new(self, property_name, value)
82
+ else
83
+ NESW.each do |orientation|
84
+ @properties[orientation].send("#{property_name}=", value)
85
+ end
86
+ end
30
87
  else
31
88
  expand_property value if value
32
89
  end
@@ -34,9 +91,10 @@ module CSS
34
91
 
35
92
  def default_properties
36
93
  @@default_properties ||= {
37
- 'size' => Property.create('size', '3px'),
38
- 'style' => nil,
39
- 'color' => Property.create('color', 'black')
94
+ 'top' => BorderOrientationProperty.new(self, 'top'),
95
+ 'right' => BorderOrientationProperty.new(self, 'right'),
96
+ 'bottom' => BorderOrientationProperty.new(self, 'bottom'),
97
+ 'left' => BorderOrientationProperty.new(self, 'left')
40
98
  }
41
99
  end
42
100
 
@@ -45,7 +103,9 @@ module CSS
45
103
 
46
104
  val = values.pop
47
105
  if val =~ /^(#|rgb)/ || Colors::NAMES.include?(val.upcase)
48
- @properties["color"] = Property.create('color', val)
106
+ NESW.each do |o|
107
+ @properties[o].send('color=', val)
108
+ end
49
109
  else
50
110
  values << val
51
111
  end
@@ -54,11 +114,19 @@ module CSS
54
114
  if val =~ /^\d/
55
115
  values << val
56
116
  else
57
- @properties["style"] = Property.create('style', val) if val
117
+ if val
118
+ NESW.each do |o|
119
+ @properties[o].send('style=', val)
120
+ end
121
+ end
58
122
  end
59
123
 
60
124
  val = values.pop
61
- @properties["size"] = Property.create('size', val) if val
125
+ if val
126
+ NESW.each do |o|
127
+ @properties[o].send('size=', val)
128
+ end
129
+ end
62
130
  end
63
131
  end
64
132
  end
@@ -0,0 +1,16 @@
1
+ module CSS
2
+ class BorderUnitProperty < MarginProperty
3
+ def init(parent, name, value)
4
+ @name = name
5
+ super
6
+ end
7
+
8
+ def name
9
+ @name
10
+ end
11
+
12
+ def to_style
13
+ [@parent.try(:name), super].compact.join('-')
14
+ end
15
+ end
16
+ end
@@ -4,30 +4,14 @@ module CSS
4
4
  'font'
5
5
  end
6
6
 
7
- def to_s
8
- if size && family
9
- %w(style variant weight size family).map do |prop|
10
- if @properties[prop] != default_properties[prop]
11
- if prop == 'size' && get('size') != nil && @properties['line-height']
12
- [@properties[prop], @properties['line-height']].join('/')
13
- else
14
- @properties[prop]
15
- end
16
- else
17
- nil
18
- end
19
- end.compact.join(' ')
20
- end
21
- end
22
-
23
7
  def to_style
24
8
  if size && family
25
9
  values = %w(style variant weight size family).map do |prop|
26
10
  if @properties[prop] != default_properties[prop]
27
11
  if prop == 'size' && get('size') != nil && @properties['line-height']
28
- [@properties[prop], @properties['line-height']].join('/')
12
+ [@properties[prop].value, @properties['line-height'].value].join('/')
29
13
  else
30
- @properties[prop]
14
+ @properties[prop].try(:value)
31
15
  end
32
16
  else
33
17
  nil
@@ -35,17 +19,18 @@ module CSS
35
19
  end.compact.join(' ')
36
20
  [name, values].join(':')
37
21
  else
38
- @properties.map { |prop, val| "#{prop == 'line-height' ? '' : 'font-'}#{prop}:#{val}" }.join(';')
22
+ @properties.map { |property_name, property| "#{property_name == 'line-height' ? '' : 'font-'}#{property_name}:#{property.value}" }.join(';')
39
23
  end
40
24
  end
41
25
 
42
26
  private
43
- def init(name, value)
27
+ def init(parent, name, value)
28
+ @parent = parent
44
29
  if name == 'line-height'
45
30
  @properties['line-height'] = Property.new(:p, 'line-height', value)
46
31
  elsif name =~ /-/
47
32
  property_name = name.sub(/[^-]+-(.*)/, '\1')
48
- @properties[property_name] = Property.new(:p, property_name, value)
33
+ @properties[property_name] = Property.new(self, property_name, value)
49
34
  else
50
35
  expand_property value if value
51
36
  end
@@ -53,11 +38,11 @@ module CSS
53
38
 
54
39
  def default_properties
55
40
  @@default_properties ||= {
56
- 'style' => Property.new(:p, 'style', 'normal'),
57
- 'variant' => Property.new(:p, 'variant', 'normal'),
58
- 'weight' => Property.new(:p, 'weight', 'normal'),
59
- 'size' => Property.new(:p, 'size', 'inherit'),
60
- 'family' => Property.new(:p, 'family', 'inherit'),
41
+ 'style' => Property.new(self, 'style', 'normal'),
42
+ 'variant' => Property.new(self, 'variant', 'normal'),
43
+ 'weight' => Property.new(self, 'weight', 'normal'),
44
+ 'size' => Property.new(self, 'size', 'inherit'),
45
+ 'family' => Property.new(self, 'family', 'inherit'),
61
46
  'line-height' => nil
62
47
  }
63
48
  end
@@ -70,29 +55,29 @@ module CSS
70
55
  if font_families[0] =~ /"\s*$/
71
56
  font_families[0] = [values.pop, font_families[0]].join(' ')
72
57
  end
73
- @properties['family'] = Property.new(:p, 'family', font_families.join(','))
58
+ @properties['family'] = Property.new(self, 'family', font_families.join(','))
74
59
 
75
60
  val = values.pop
76
61
  font_size, line_height = val.split(/\//)
77
- @properties['size'] = Property.new(:p, 'size', font_size)
62
+ @properties['size'] = Property.new(self, 'size', font_size)
78
63
  @properties['line-height'] = Property.new(:p, 'line-height', line_height) if line_height
79
64
 
80
65
  val = values.shift
81
66
  if val =~ /(inherit|italic|oblique)/
82
- @properties['style'] = Property.new(:p, 'style', val)
67
+ @properties['style'] = Property.new(self, 'style', val)
83
68
  else
84
69
  values << val
85
70
  end
86
71
 
87
72
  val = values.shift
88
73
  if val =~ /(inherit|small-caps)/
89
- @properties['variant'] = Property.new(:p, 'variant', val)
74
+ @properties['variant'] = Property.new(self, 'variant', val)
90
75
  else
91
76
  values << val
92
77
  end
93
78
 
94
79
  val = values.shift
95
- @properties['weight'] = Property.new(:p, 'weight', val) if val
80
+ @properties['weight'] = Property.new(self, 'weight', val) if val
96
81
  end
97
82
  end
98
83
  end
@@ -5,16 +5,17 @@ module CSS
5
5
  super
6
6
  end
7
7
 
8
- def name
9
- 'list-style'
8
+ def get(property_name)
9
+ @properties[property_name]
10
10
  end
11
11
 
12
- def to_s
13
- %w(type position image).map { |prop| @properties[prop] }.join(' ')
12
+ def name
13
+ 'list-style'
14
14
  end
15
15
 
16
16
  def to_style
17
- [name, to_s].join(':')
17
+ value = %w(type position image).map { |prop| @properties[prop].try(:value) }.join(' ')
18
+ [name, value].join(':')
18
19
  end
19
20
 
20
21
  def type
@@ -22,19 +23,21 @@ module CSS
22
23
  end
23
24
 
24
25
  def type=(val)
25
- @properties['type'] = val
26
+ @properties['type'] = Property.new(self, 'type', val)
26
27
  end
27
28
 
28
29
  private
29
- def init(name, value)
30
+ def init(parent, name, value)
31
+ @parent = parent
32
+ @properties['image'] = Property.new(self, 'image', 'none')
30
33
  expand_property value if value
31
34
  end
32
35
 
33
36
  def default_properties
34
37
  @@default_properties ||= {
35
- 'type' => Property.new(:p, 'type', 'disc'),
36
- 'position' => Property.new(:p, 'position', 'outside'),
37
- 'image' => Property.new(:p, 'image', 'none')
38
+ 'type' => Property.new(self, 'type', 'disc'),
39
+ 'position' => Property.new(self, 'position', 'outside'),
40
+ 'image' => Property.new(self, 'image', 'none')
38
41
  }
39
42
  end
40
43
 
@@ -43,11 +46,11 @@ module CSS
43
46
  while values.size > 0
44
47
  val = values.shift
45
48
  if val =~ /^url/
46
- @properties['image'] = Property.new(:p, 'image', val)
49
+ @properties['image'] = Property.new(self, 'image', val)
47
50
  elsif val =~ /^(inside|outside)/
48
- @properties['position'] = Property.new(:p, 'position', val)
51
+ @properties['position'] = Property.new(self, 'position', val)
49
52
  else
50
- @properties['type'] = Property.new(:p, 'type', val)
53
+ @properties['type'] = Property.new(self, 'type', val)
51
54
  end
52
55
  end
53
56
  end
@@ -1,25 +1,28 @@
1
+ require 'css/helpers/orientation'
2
+
1
3
  module CSS
2
4
  class MarginProperty < Property
5
+ include Orientation
6
+
3
7
  def name
4
8
  'margin'
5
9
  end
6
10
 
7
- def to_s
11
+ def ==(val)
12
+ if val.is_a?(Property)
13
+ super
14
+ else
15
+ value == val
16
+ end
17
+ end
18
+
19
+ def value
8
20
  top = @properties['top']
9
21
  right = @properties['right']
10
22
  bottom = @properties['bottom']
11
23
  left = @properties['left']
12
-
13
24
  if top && right && bottom && left
14
- if [top, right, bottom, left] == Array.new(4) { top }
15
- top
16
- elsif [top, bottom] == Array.new(2) { top } && [left, right] == Array.new(2) { left }
17
- [top, left].join(' ')
18
- elsif [top, bottom] != Array.new(2) { top } && [left, right] == Array.new(2) { left }
19
- [top, left, bottom].join(' ')
20
- else
21
- [top, right, bottom, left].join(' ')
22
- end
25
+ compact_orientation(top, right, bottom, left)
23
26
  end
24
27
  end
25
28
 
@@ -30,26 +33,19 @@ module CSS
30
33
  left = @properties['left']
31
34
 
32
35
  if top && right && bottom && left
33
- value = if [top, right, bottom, left] == Array.new(4) { top }
34
- top
35
- elsif [top, bottom] == Array.new(2) { top } && [left, right] == Array.new(2) { left }
36
- [top, left].join(' ')
37
- elsif [top, bottom] != Array.new(2) { top } && [left, right] == Array.new(2) { left }
38
- [top, left, bottom].join(' ')
39
- else
40
- [top, right, bottom, left].join(' ')
41
- end
36
+ value = compact_orientation(top, right, bottom, left)
42
37
  [name, value].join(':')
43
38
  else
44
- default_properties.keys.map { |prop| @properties[prop] ? ["#{name}-#{prop}", @properties[prop]].join(':') : nil }.compact.join(';')
39
+ default_properties.keys.map { |prop| @properties[prop] ? ["#{name}-#{prop}", @properties[prop].value].join(':') : nil }.compact.join(';')
45
40
  end
46
41
  end
47
42
 
48
43
  private
49
- def init(name, value)
44
+ def init(parent, name, value)
45
+ @parent = parent
50
46
  if name =~ /-/
51
47
  property_name = name.sub(/[^-]+-(.*)/, '\1')
52
- @properties[property_name] = Property.new(:p, property_name, value)
48
+ @properties[property_name] = Property.new(self, property_name, value)
53
49
  else
54
50
  expand_property value if value
55
51
  end
@@ -90,10 +86,10 @@ module CSS
90
86
  left = values[3]
91
87
  end
92
88
 
93
- @properties['top'] = Property.new(:p, 'top', top)
94
- @properties['right'] = Property.new(:p, 'right', right)
95
- @properties['bottom'] = Property.new(:p, 'bottom', bottom)
96
- @properties['left'] = Property.new(:p, 'left', left)
89
+ @properties['top'] = Property.new(self, 'top', top)
90
+ @properties['right'] = Property.new(self, 'right', right)
91
+ @properties['bottom'] = Property.new(self, 'bottom', bottom)
92
+ @properties['left'] = Property.new(self, 'left', left)
97
93
  end
98
94
  end
99
95
  end
@@ -1,17 +1,21 @@
1
+ require 'css/helpers/normalize'
2
+
1
3
  module CSS
2
4
  class Property
3
5
  include Normalize
4
6
 
5
- attr_reader :name
7
+ attr_reader :value
6
8
 
7
9
  def initialize(*args)
8
- raise "Please use Property.create instead of Property.new" unless args[0] == :p
9
- @properties ||= {}
10
- init(args[1], args[2])
10
+ raise "Please use Property.create instead of Property.new" unless args[0] == :p || args[0].is_a?(Property)
11
+ @properties = {}
12
+ name = args[1]
13
+ value = clean_value(args[2])
14
+ init(args[0].is_a?(Property) ? args[0] : nil, name, value)
11
15
  end
12
16
 
13
17
  def self.create(name, value = nil)
14
- klass = case name
18
+ klass = case name.to_s
15
19
  when /^background/
16
20
  BackgroundProperty
17
21
  when /^(font|line-height)/
@@ -37,30 +41,46 @@ module CSS
37
41
  @properties.keys.include?(normalize_property_name(property_name))
38
42
  end
39
43
 
40
- def to_s
41
- @value
44
+ def name
45
+ [@parent.try(:name), @name].compact.join('-')
46
+ end
47
+
48
+ def value=(val)
49
+ if @properties.size > 0
50
+ expand_property val
51
+ else
52
+ @value = val
53
+ end
42
54
  end
43
55
 
44
- def value
45
- to_s
56
+ def to_s
57
+ @value || to_style
46
58
  end
47
59
 
48
60
  def inspect
49
- to_s
61
+ "#<Property #{to_style}>"
50
62
  end
51
63
 
52
64
  def to_style
53
- [@name, @value].join(':')
65
+ [name, @value].join(':')
54
66
  end
55
67
 
56
68
  def ==(val)
57
69
  if val.is_a?(Property)
58
- @value == val.value
70
+ @value == val.instance_variable_get(:@value) && @properties == val.instance_variable_get(:@properties)
59
71
  else
60
72
  @value == val
61
73
  end
62
74
  end
63
75
 
76
+ def eql?(property)
77
+ property.is_a?(Property) && self == property
78
+ end
79
+
80
+ def hash
81
+ to_style.hash
82
+ end
83
+
64
84
  def <<(val)
65
85
  @value = val
66
86
  end
@@ -97,8 +117,18 @@ module CSS
97
117
  end
98
118
  end
99
119
 
120
+ def respond_to?(method_name, include_private = false)
121
+ property_name = normalize_property_name(method_name.to_s[-1..-1] == '=' ? method_name.to_s.chop : method_name)
122
+ default_properties.keys.include?(property_name) || super
123
+ end
124
+
125
+ def empty?
126
+ @value.nil? && @properties.all? { |p| p.empty? }
127
+ end
128
+
100
129
  private
101
- def init(name, value)
130
+ def init(parent, name, value)
131
+ @parent = parent
102
132
  @name = name
103
133
  @value = value
104
134
  end
@@ -106,13 +136,24 @@ module CSS
106
136
  def default_properties
107
137
  {}
108
138
  end
139
+
140
+ def clean_value(value)
141
+ return if value.nil?
142
+
143
+ value = value.
144
+ to_s.
145
+ strip.
146
+ gsub(/rgba?\([^)]+\)/) { |match| match.delete(' ') }
147
+ end
109
148
  end
110
149
  end
111
150
 
151
+ require "css/properties/margin_property.rb"
112
152
  require "css/properties/background_property.rb"
113
153
  require "css/properties/font_property.rb"
114
154
  require "css/properties/border_property.rb"
155
+ require "css/properties/border_orientation_property.rb"
156
+ require "css/properties/border_unit_property.rb"
115
157
  require "css/properties/outline_property.rb"
116
- require "css/properties/margin_property.rb"
117
158
  require "css/properties/padding_property.rb"
118
159
  require "css/properties/list_style_property.rb"
@@ -1,5 +1,6 @@
1
1
  # Shorthand conversions based on guide by Dustin Diaz - http://www.dustindiaz.com/css-shorthand/
2
2
  require 'set'
3
+ require 'css/helpers/normalize'
3
4
 
4
5
  module CSS
5
6
  class Rule
@@ -28,13 +29,49 @@ module CSS
28
29
  end
29
30
 
30
31
  def get(property_name)
31
- @rules[normalize_property_name(property_name)]
32
+ property_name = normalize_property_name(property_name)
33
+ if property_name =~ /-/
34
+ property_name_parts = property_name.split('-')
35
+ pname = property_name_parts.shift
36
+ property = nil
37
+ while property_name_parts.size > 0
38
+ property = @rules[normalize_property_name(pname)]
39
+ break unless property.nil?
40
+ pname = [pname, property_name_parts.shift].join('-')
41
+ end
42
+ property = @rules[normalize_property_name(pname)] unless property
43
+ if property && property_name_parts.size == 0
44
+ property
45
+ else
46
+ while property_name_parts.size > 0
47
+ next_property_name = property_name_parts.shift
48
+ property = property[next_property_name] if property
49
+ end
50
+ property
51
+ end
52
+ else
53
+ @rules[normalize_property_name(property_name)]
54
+ end
32
55
  end
33
56
 
34
57
  def [](property_name)
35
58
  get property_name
36
59
  end
37
60
 
61
+ def []=(property_name, value)
62
+ property = get(property_name)
63
+ unless property
64
+ property = Property.create(property_name, value)
65
+ if @rules[property.name]
66
+ @rules[property.name] << property
67
+ else
68
+ @properties << property.name
69
+ @rules[property.name] = property
70
+ end
71
+ end
72
+ property.value = value
73
+ end
74
+
38
75
  def to_s
39
76
  properties.map { |prop| get(prop).to_style }.join ';'
40
77
  end
@@ -48,43 +85,22 @@ module CSS
48
85
  end
49
86
 
50
87
  def has_property?(property_name)
51
- property_name = normalize_property_name(property_name)
52
- if property_name =~ /-/
53
- property_name_parts = property_name.split('-')
54
- pname = property_name_parts.shift
55
- property = nil
56
- while property_name_parts.size > 0
57
- property = get(pname)
58
- break unless property.nil?
59
- pname = [pname, property_name_parts.shift].join('-')
60
- end
61
- property.has_property?(property_name_parts.shift)
62
- else
63
- properties.include?(property_name)
64
- end
88
+ !get(property_name).empty?
65
89
  end
66
90
 
67
91
  def method_missing(method_name, *args)
68
- property_name = normalize_property_name(method_name)
69
- if property_name =~ /-/
70
- property_name_parts = property_name.split('-')
71
- pname = property_name_parts.shift
72
- property = nil
73
- while property_name_parts.size > 0
74
- property = get(pname)
75
- break unless property.nil?
76
- pname = [pname, property_name_parts.shift].join('-')
77
- end
78
- property[property_name_parts.shift]
92
+ if method_name.to_s[-1..-1] == '='
93
+ property_name = method_name.to_s.chop
94
+ self[property_name] = args[0]
79
95
  else
80
- get(property_name) || super
96
+ get(method_name) || super
81
97
  end
82
98
  end
83
99
 
84
100
  private
85
101
  def parse_rules(properties, rules, rule_text)
86
102
  rule_text.split(/;/).inject([properties, rules]) do |properties, rule|
87
- property = rule.split(/:/).map { |el| el.strip }
103
+ property = rule.split(/:/)
88
104
  name = normalize_property_name(property[0])
89
105
  value = property[1]
90
106
 
@@ -1,9 +1,7 @@
1
- require 'set'
2
-
3
1
  module CSS
4
2
  class RuleSet
5
3
  def initialize
6
- @selectors = Set.new
4
+ @selectors = []
7
5
  @rules = {}
8
6
  end
9
7
 
@@ -25,15 +23,11 @@ module CSS
25
23
  end
26
24
 
27
25
  def rules
28
- selectors.map { |selector| @rules[selector] }
26
+ selectors.map { |s| @rules[s] }
29
27
  end
30
28
 
31
29
  def to_style
32
- rules = []
33
- selectors.each do |selector|
34
- rules << @rules[selector].to_style
35
- end
36
- rules.join("\n")
30
+ rules.map { |rule| rule.to_style }.join("\n")
37
31
  end
38
32
  end
39
33
  end
@@ -0,0 +1,15 @@
1
+ unless Object.methods.include?('try')
2
+ class Object
3
+ def try(method_name, *args)
4
+ send(method_name, *args) if respond_to?(method_name, true)
5
+ end
6
+ end
7
+ end
8
+
9
+ unless NilClass.methods.include?('empty?')
10
+ class NilClass
11
+ def empty?
12
+ true
13
+ end
14
+ end
15
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: css
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 3
10
- version: 0.0.3
9
+ - 4
10
+ version: 0.0.4
11
11
  platform: ruby
12
12
  authors:
13
13
  - Andrew Timberlake
@@ -46,10 +46,13 @@ files:
46
46
  - LICENSE
47
47
  - lib/css/colors.rb
48
48
  - lib/css/errors.rb
49
- - lib/css/normalize.rb
49
+ - lib/css/helpers/normalize.rb
50
+ - lib/css/helpers/orientation.rb
50
51
  - lib/css/parser.rb
51
52
  - lib/css/properties/background_property.rb
53
+ - lib/css/properties/border_orientation_property.rb
52
54
  - lib/css/properties/border_property.rb
55
+ - lib/css/properties/border_unit_property.rb
53
56
  - lib/css/properties/font_property.rb
54
57
  - lib/css/properties/list_style_property.rb
55
58
  - lib/css/properties/margin_property.rb
@@ -59,6 +62,7 @@ files:
59
62
  - lib/css/rule.rb
60
63
  - lib/css/rule_set.rb
61
64
  - lib/css.rb
65
+ - lib/monkey_patches.rb
62
66
  - lib/numbers.rb
63
67
  - README.rdoc
64
68
  has_rdoc: true
@@ -1,15 +0,0 @@
1
- module CSS
2
- module Normalize
3
- def normalize_property_name(name)
4
- if name.to_s =~ /[A-Z]/
5
- name.to_s.gsub(/([A-Z])/) do |match|
6
- "-#{match.downcase}"
7
- end
8
- elsif name.to_s =~ /_/
9
- name.to_s.gsub(/_/, '-')
10
- else
11
- name.to_s
12
- end
13
- end
14
- end
15
- end