css 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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