mirror-mirror 0.0.1 → 0.9.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
2
  SHA1:
3
- metadata.gz: 440d5c08e81aa2644a219d9bb39f6cca9ac5b91e
4
- data.tar.gz: 72a68f59655f65ee4a13c9f812fdbaa8bfca9313
3
+ metadata.gz: 14586345e6e0083164bf05e65d57bc096676491e
4
+ data.tar.gz: 38813d5fea803d5c7b36e1277fd74e9950d22687
5
5
  SHA512:
6
- metadata.gz: 505d1fd16b3e97bbcaa6fe8f763347b2c43952e74c15f8f8769c70ac344d127d5936702365765942b3891c4740499202200a51d190e2b5397cdb86ef7bf78ba8
7
- data.tar.gz: 910d676de83793404e0dd9ef0c93ad5b074baf1e265490a2aaf8c1e2e12f6b83f7368fe14840887e880e92dfdff34c118fc803d6686f7159bb36373fde27ab8b
6
+ metadata.gz: 82e25a14ddac18c555010a536d94ab023eec33f7bc041e2b04a064773667c3bc2a74cad3f946ddafa3694cea3632b5320c1735eed5c7bc3192a7eb2ef974b676
7
+ data.tar.gz: 2bd76bcc6790fea53366a0c315ed6f8e9c4d5eb4549a7d3ff2fadcf366f82d54bf0b77edbff64659dc977a1180db65899abed05760f01a000b782fed195c8f25
@@ -0,0 +1,3 @@
1
+ require 'mirror-mirror'
2
+
3
+ MirrorMirror.activate!
@@ -0,0 +1,195 @@
1
+ require 'mirror-mirror/transformation'
2
+
3
+ module MirrorMirror
4
+ class MirrorVisitor < Sass::Tree::Visitors::Base
5
+ def initialize
6
+ @in_meta_directive = false
7
+ @nested = false
8
+ @enabled = false
9
+ @inline = false
10
+ @options = {}
11
+ @property_transformers = Transformation::PropertyTransformation.instances
12
+ @debug = false
13
+ end
14
+
15
+ def visit_root(root_node)
16
+ # XXX set up defaults from options
17
+ @options = root_node.options
18
+ @enabled = true if @options[:custom] && @options[:custom][:mirror_mirror] == true
19
+ root_node.children = yield
20
+ root_node
21
+ end
22
+
23
+ def visit(node)
24
+ method = "visit_#{node_name node}"
25
+ if self.respond_to?(method, true)
26
+ self.send(method, node) {node.children = visit_children(node)}
27
+ else
28
+ node.children = visit_children(node)
29
+ node
30
+ end
31
+ end
32
+
33
+ def visit_children(parent)
34
+ r = super
35
+ r.flatten!
36
+ r.compact!
37
+ r
38
+ end
39
+
40
+ def visit_rule(rule_node)
41
+ puts "RULE: #{rule_node.resolved_rules}" if @debug
42
+ @nested = true;
43
+ yield
44
+ @nested = false;
45
+ rule_node
46
+ end
47
+
48
+ def visit_prop(prop_node)
49
+ if @in_meta_directive && prop_node.resolved_name == "enabled"
50
+ @enabled = prop_node.resolved_value == "true"
51
+ #if @nested
52
+ #raise Sass::SyntaxError, "Cannot #{@enabled ? 'enable' : 'disable'} mirror flipping in a nested context"
53
+ #end
54
+ puts @enabled ? "ENABLED" : "DISABLED" if @debug
55
+ return prop_node
56
+ end
57
+
58
+ puts "PROPERTY: #{prop_node.resolved_name}" if @debug
59
+ unless @enabled
60
+ return prop_node
61
+ end
62
+
63
+ prop_name = prop_node.resolved_name.downcase
64
+ value = prop_node.resolved_value
65
+ prefix, prop_name = $1, $2 if prop_name =~ /^(\*|_|#|-moz-|-ms-|-webkit-|-o-)(.*)$/
66
+ original_name = prop_name
67
+ original_value = value
68
+ important = nil
69
+
70
+ if value =~ /^(.*[^ ])( *!important *)$/
71
+ value, important = $1, $2
72
+ end
73
+
74
+ property_transformers(prop_name, :name).each do |t|
75
+ prop_name = t.transform_name(prop_name)
76
+ end
77
+
78
+ property_transformers(original_name, :value).each do |t|
79
+ value = t.transform_value(original_name, value)
80
+ end
81
+
82
+ expression = nil
83
+ begin
84
+ property_transformers(original_name, :expression).each do |t|
85
+ expression ||= parsed_value(value, prop_node.line, original_name.size)
86
+ expression = t.transform_expression(original_name, expression)
87
+ end
88
+ rescue Sass::SyntaxError => e
89
+ Sass.logger.warn("Syntax error during mirror flip of `#{original_name}: #{original_value}`: #{e.message}")
90
+ return prop_node
91
+ end
92
+ begin
93
+ value = literalize(expression).to_s(@options) if expression
94
+ rescue => e
95
+ Sass.logger.warn "Failed to stringify the transformation of `#{original_name}: #{original_value}`: #{e.message} (#{expression.class.name})"
96
+ Sass.logger.warn(e.backtrace.join("\n"))
97
+ value = original_value
98
+ end
99
+
100
+ if @debug && prop_node.resolved_name != "#{prefix}#{prop_name}"
101
+ puts "CHANGED name FROM #{prop_node.resolved_name} TO #{prefix}#{prop_name}"
102
+ end
103
+ if @debug && prop_node.resolved_value != value
104
+ puts "CHANGED value FROM #{prop_node.resolved_value} TO #{value}"
105
+ end
106
+ prop_node.resolved_name = "#{prefix}#{prop_name}"
107
+ prop_node.resolved_value = "#{value}#{important}"
108
+ prop_node
109
+ end
110
+
111
+ def visit_directive(directive_node)
112
+ if directive_node.resolved_value.strip == "@-mirror-mirror"
113
+ @in_meta_directive = true
114
+ begin
115
+ yield
116
+ ensure
117
+ @in_meta_directive = false
118
+ end
119
+ nil # remove this node from the output
120
+ elsif directive_node.resolved_value.strip == "@-mirror-mirror no-flip"
121
+ old_enabled = @enabled
122
+ @enabled = false
123
+ begin
124
+ yield
125
+ directive_node.children
126
+ ensure
127
+ @enabled = old_enabled
128
+ end
129
+ elsif directive_node.resolved_value.strip == "@-mirror-mirror inline-flip"
130
+ old_inline = @inline
131
+ old_enabled = @enabled
132
+ @inline = true
133
+ @enabled = true
134
+ begin
135
+ yield
136
+ directive_node.children
137
+ ensure
138
+ @enabled = old_enabled
139
+ @inline = old_inline
140
+ end
141
+ else
142
+ yield
143
+ directive_node
144
+ end
145
+ end
146
+
147
+ protected
148
+
149
+ def property_transformers(name, type)
150
+ @propert_transformers_by_property ||= {}
151
+ @propert_transformers_by_property[name] ||= {}
152
+ @propert_transformers_by_property[name][type] ||= begin
153
+ @property_transformers.select {|t| t.send(:"transform_#{type}?", name)}
154
+ end
155
+ end
156
+
157
+ def parsed_value(value, line, offset)
158
+ slashify(Sass::Script::Parser.new(value, line, offset).parse)
159
+ end
160
+
161
+ def literalize(expression)
162
+ case expression
163
+ when Sass::Script::List
164
+ expression.value.map!{|v| literalize(v) }
165
+ expression
166
+ when Sass::Script::Funcall
167
+ expression.send(:to_literal, expression.args.map {|a| literalize(a) })
168
+ else
169
+ expression
170
+ end
171
+ end
172
+
173
+ def slashify(expression)
174
+ result = _slashify(expression)
175
+ if result.is_a?(Array)
176
+ result = Sass::Script::List.new(result, :space)
177
+ result.options = expression.options
178
+ end
179
+ result
180
+ end
181
+
182
+ def _slashify(expression)
183
+ if expression.is_a?(Sass::Script::List)
184
+ expression.value.map! {|v| _slashify(v) }
185
+ expression.value.flatten!
186
+ elsif expression.is_a?(Sass::Script::Operation)
187
+ operator = Sass::Script::String.new(Sass::Script::Lexer::OPERATORS_REVERSE[expression.operator])
188
+ operator.options = expression.options
189
+ return [_slashify(expression.operand1), operator, _slashify(expression.operand2)]
190
+ end
191
+ expression
192
+ end
193
+
194
+ end
195
+ end
@@ -0,0 +1,5 @@
1
+ module Sass::Script::Functions
2
+ def mirror_mirror_enabled_by_default
3
+ Sass::Script::Bool.new(options[:custom] && options[:custom][:mirror_mirror] == true)
4
+ end
5
+ end
@@ -0,0 +1,62 @@
1
+ require 'mirror-mirror/mirror_visitor'
2
+
3
+ module MirrorMirror
4
+ # Sass should provide hooks for getting access to the AST a various stages of transformation.
5
+ # So that we don't have to monkeypatch it.
6
+ module SassPatch
7
+ def self.included(base)
8
+ if base.respond_to?(:css_tree, true)
9
+ # Sass >= 3.3
10
+ base.send(:alias_method, :css_tree_without_mirror_mirror, :css_tree)
11
+ base.send(:alias_method, :css_tree, :css_tree_with_mirror_mirror)
12
+ else
13
+ # Sass < 3.3
14
+ base.send(:alias_method, :render_without_mirror_mirror, :render)
15
+ base.send(:alias_method, :render, :render_with_mirror_mirror)
16
+ end
17
+ end
18
+
19
+ def css_tree_with_mirror_mirror
20
+ root = css_tree_without_mirror_mirror
21
+ MirrorVisitor.visit(root)
22
+ root
23
+ end
24
+
25
+ def render_with_mirror_mirror
26
+ Sass::Tree::Visitors::CheckNesting.visit(self)
27
+ result = Sass::Tree::Visitors::Perform.visit(self)
28
+ Sass::Tree::Visitors::CheckNesting.visit(result) # Check again to validate mixins
29
+ result, extends = Sass::Tree::Visitors::Cssize.visit(result)
30
+ Sass::Tree::Visitors::Extend.visit(result, extends)
31
+ MirrorVisitor.visit(result)
32
+ result.to_s
33
+ end
34
+ end
35
+
36
+ module CssizePatch
37
+ def visit_directive(directive)
38
+ if directive.resolved_value.start_with?("@-mirror-mirror")
39
+ did_bubble = bubble(directive)
40
+ yield unless did_bubble
41
+ directive
42
+ else
43
+ yield
44
+ directive
45
+ end
46
+ end
47
+ end
48
+
49
+ module DirectiveNodePatch
50
+ def self.included(base)
51
+ base.send(:attr_accessor, :group_end)
52
+ end
53
+
54
+ def bubbles?
55
+ if resolved_value
56
+ resolved_value.start_with?("@-mirror-mirror")
57
+ else
58
+ value.first.start_with?("@-mirror-mirror")
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,114 @@
1
+ module MirrorMirror::Transformation
2
+ class BackgroundPosition < PropertyTransformation
3
+ def transform_expression?(name)
4
+ name == "background" || name == "background-position" || name == "background-position-x"
5
+ end
6
+
7
+ def transform_expression(name, expression)
8
+ for_each_value(expression) do |e|
9
+ if name == "background"
10
+ transform_background(e)
11
+ else
12
+ transform_background_position(e)
13
+ end
14
+ end
15
+ end
16
+
17
+ def transform_background(expression)
18
+ unless expression.is_a?(Sass::Script::List)
19
+ expression = opts(expression.options) do
20
+ Sass::Script::List.new([expression], :space)
21
+ end
22
+ end
23
+ positions = []
24
+ position_indices = []
25
+ expression.value.each_with_index do |v, i|
26
+ if legal_as_background_position?(v)
27
+ positions << v
28
+ position_indices << i
29
+ else
30
+ break if positions.any?
31
+ next
32
+ end
33
+ positions
34
+ end
35
+ return expression unless positions.any?
36
+ if positions.size > 2
37
+ require 'pry'
38
+ binding.pry
39
+ Sass.logger.warn("Line #{expression.line}: malformed background: #{expression.to_sass}")
40
+ return expression
41
+ end
42
+ # tranform the background position elements and replace the position
43
+ # section of the shorthand with it
44
+ transformed = transform_background_position(Sass::Script::List.new(positions, :space))
45
+ position_indices << position_indices.first if position_indices.size < 2
46
+ expression.value[Range.new(*position_indices)] = transformed.value
47
+ expression
48
+ end
49
+
50
+ def transform_background_position(expression)
51
+ unless expression.is_a?(Sass::Script::List)
52
+ expression = opts(expression.options) do
53
+ Sass::Script::List.new([expression], :space)
54
+ end
55
+ end
56
+ if expression.value.size > 2
57
+ # positions with offsets
58
+ expression.value.each_with_index do |e, i|
59
+ next if i % 2 == 1
60
+ expression.value[i] = flip_it(e, i / 2)
61
+ end
62
+ else
63
+ # positions
64
+ expression.value.each_with_index do |e, i|
65
+ expression.value[i] = flip_it(e, i)
66
+ end
67
+ end
68
+ expression
69
+ end
70
+
71
+ ONE_HUNDRED_PERCENT = Sass::Script::Number.new(100, ["%"], [])
72
+
73
+ def flip_it(e, position)
74
+ return e unless e.respond_to?(:value)
75
+ case e
76
+ when Sass::Script::Number
77
+ if position == 0 && e.value == 0
78
+ opts(e.options) { ONE_HUNDRED_PERCENT.dup }
79
+ elsif position == 0 && e.numerator_units.first == "%"
80
+ opts(e.options) { ONE_HUNDRED_PERCENT.minus(e) }
81
+ elsif position == 0
82
+ Sass.logger.warn("Line #{e.line}: Cannot flip background position: #{e}")
83
+ e
84
+ else
85
+ e
86
+ end
87
+ when Sass::Script::String
88
+ case e.value
89
+ when "right"
90
+ e.value.replace("left")
91
+ when "left"
92
+ e.value.replace("right")
93
+ end
94
+ e
95
+ else
96
+ e
97
+ end
98
+ end
99
+
100
+ POSITION_KEYWORDS = Set.new(%w(top bottom left right center))
101
+
102
+ def legal_as_background_position?(e)
103
+ case e
104
+ when Sass::Script::String
105
+ POSITION_KEYWORDS.include?(e.value)
106
+ when Sass::Script::Number
107
+ true
108
+ else
109
+ false
110
+ end
111
+ end
112
+ end
113
+ end
114
+
@@ -0,0 +1,18 @@
1
+ require 'singleton'
2
+
3
+ module MirrorMirror::Transformation
4
+ class Base
5
+ include Singleton
6
+
7
+ def self.inherited(subclass)
8
+ super
9
+ @subclasses ||= []
10
+ @subclasses << subclass
11
+ end
12
+
13
+ def self.instances
14
+ @subclasses.map {|c| c.instance }
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,39 @@
1
+ module MirrorMirror::Transformation
2
+ class BorderRadius < PropertyTransformation
3
+ def transform_value?(name)
4
+ name == "border-radius"
5
+ end
6
+
7
+ def transform_value(name, value)
8
+ values = value.split(/ +/)
9
+ h_radii = []
10
+ v_radii = []
11
+ has_separator = false
12
+ values.each do |v|
13
+ if v == "/"
14
+ has_separator = true
15
+ next
16
+ end
17
+ if has_separator
18
+ v_radii << v
19
+ else
20
+ h_radii << v
21
+ end
22
+ end
23
+ flip_corners!(h_radii)
24
+ flip_corners!(v_radii)
25
+ values[0...h_radii.size] = h_radii
26
+ if v_radii.any?
27
+ values[(h_radii.size+1)..(h_radii.size+v_radii.size)] = v_radii
28
+ end
29
+ values.join(" ")
30
+ end
31
+
32
+ def flip_corners!(list)
33
+ list[0], list[1] = list[1], list[0] if list.size > 1
34
+ list[2], list[3] = list[3], list[2] if list.size > 3
35
+ nil
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,32 @@
1
+ module MirrorMirror::Transformation
2
+ class BoxShadow < PropertyTransformation
3
+ def transform_expression?(name)
4
+ name == "box-shadow"
5
+ end
6
+
7
+ NEGATIVE_ONE = Sass::Script::Number.new(-1)
8
+
9
+ def transform_expression(name, expression)
10
+ for_each_value(expression) do |e|
11
+ case e
12
+ when Sass::Script::List
13
+ if e.value[0].is_a?(Sass::Script::Number)
14
+ e.value[0] = flip_it(e.value[0])
15
+ end
16
+ when Sass::Script::Number
17
+ e = flip_it(e)
18
+ end
19
+ e
20
+ end
21
+ end
22
+
23
+ def flip_it(expression)
24
+ opts(expression.options) do
25
+ expression.times(NEGATIVE_ONE)
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+
32
+
@@ -0,0 +1,17 @@
1
+ module MirrorMirror::Transformation
2
+ class Cursor < PropertyTransformation
3
+ def transform_value?(name)
4
+ name == "cursor"
5
+ end
6
+
7
+ def transform_value(name, value)
8
+ if value =~ /(n|s)?(e|w)-resize/
9
+ "#{$1}#{$2 == "e" ? "w" : "e"}-resize"
10
+ else
11
+ value
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+
@@ -0,0 +1,18 @@
1
+ module MirrorMirror::Transformation
2
+ class Direction < PropertyTransformation
3
+ def transform_value?(name)
4
+ name == "direction"
5
+ end
6
+
7
+ def transform_value(name, value)
8
+ case value
9
+ when "ltr"
10
+ "rtl"
11
+ when "rtl"
12
+ "ltr"
13
+ else
14
+ value
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ module MirrorMirror::Transformation
2
+ class DirectionalProperty < PropertyTransformation
3
+ def transform_name?(name)
4
+ name =~ /left|right/
5
+ end
6
+
7
+ def transform_name(name)
8
+ name =~ /^(.*)(left|right)(.*)$/
9
+ "#{$1}#{$2 == "left" ? "right" : "left"}#{$3}"
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,18 @@
1
+ module MirrorMirror::Transformation
2
+ class Float < PropertyTransformation
3
+ def transform_value?(name)
4
+ name == "float" || name == "clear"
5
+ end
6
+
7
+ def transform_value(name, value)
8
+ case value
9
+ when "left"
10
+ "right"
11
+ when "right"
12
+ "left"
13
+ else
14
+ value
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,84 @@
1
+ require 'set'
2
+ module MirrorMirror::Transformation
3
+ class LinearGradient < PropertyTransformation
4
+ IMAGE_PROPERTIES = Set[
5
+ 'background',
6
+ 'background-image',
7
+ 'border-image',
8
+ 'list-style-image',
9
+ 'list-style',
10
+ 'content'
11
+ ]
12
+ def transform_expression?(name)
13
+ IMAGE_PROPERTIES.include?(name)
14
+ end
15
+
16
+ def transform_expression(name, expression)
17
+ for_each_value(expression) do |e|
18
+ if grad = find_linear_gradient(e)
19
+ if direction?(grad.args[0])
20
+ grad.args[0] = flip(grad.args[0])
21
+ end
22
+ e
23
+ else
24
+ e
25
+ end
26
+ end
27
+ end
28
+
29
+ def find_linear_gradient(expression)
30
+ case expression
31
+ when Sass::Script::List
32
+ expression.value.each do |v|
33
+ grad = find_linear_gradient(v)
34
+ return grad if grad
35
+ end
36
+ nil
37
+ when Sass::Script::Funcall
38
+ expression if expression.name =~ /^(-(moz|webkit|o|ms)-)?(repeating-)?linear-gradient$/
39
+ end
40
+ end
41
+
42
+ def degree?(e)
43
+ e.is_a?(Sass::Script::Number) && e.numerator_units.first == "deg"
44
+ end
45
+
46
+ DIRECTIONAL_KEYWORDS = Set.new(%w(to top left right bottom))
47
+ def directional_keywords?(e)
48
+ (e.is_a?(Sass::Script::List) && DIRECTIONAL_KEYWORDS.include?(e.value.first.value)) ||
49
+ DIRECTIONAL_KEYWORDS.include?(e.value)
50
+ end
51
+
52
+ def direction?(e)
53
+ degree?(e) || directional_keywords?(e)
54
+ end
55
+
56
+ def color_stop?(e)
57
+ e.is_a?(Sass::Script::Color) ||
58
+ (e.is_a?(Sass::Script::List) && e.value.first.is_a?(Sass::Script::Color))
59
+ end
60
+
61
+ S360 = Sass::Script::Number.new(360)
62
+ def flip(direction)
63
+ if degree?(direction)
64
+ opts(direction.options) { S360.minus(direction).mod(S360) }
65
+ else
66
+ case direction
67
+ when Sass::Script::List
68
+ direction.value.map!{|v| flip(v) }
69
+ direction
70
+ when Sass::Script::String
71
+ if direction.value == "left"
72
+ opts(direction.options) { Sass::Script::String.new("right") }
73
+ elsif direction.value == "right"
74
+ opts(direction.options) { Sass::Script::String.new("left") }
75
+ else
76
+ direction
77
+ end
78
+ else
79
+ direction
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,69 @@
1
+ module MirrorMirror::Transformation
2
+ class PropertyTransformation < Base
3
+ # The singleton instances, one for each transformation class
4
+ def self.instances
5
+ super.
6
+ select {|i| i.is_a?(PropertyTransformation) && i.class != PropertyTransformation}
7
+ end
8
+
9
+ # @param name [String] The property name
10
+ # @return [Boolean]
11
+ def transform_name?(name)
12
+ false
13
+ end
14
+
15
+ # @param name [String] The property name
16
+ def transform_name(name)
17
+ name
18
+ end
19
+
20
+ # @param name [String] The property name
21
+ # @return [Boolean]
22
+ def transform_value?(name)
23
+ false
24
+ end
25
+
26
+ # @param name [String] The property name
27
+ # @return [Boolean]
28
+ def transform_expression?(name)
29
+ false
30
+ end
31
+
32
+ # @param property [String] The property whose value is being transformed.
33
+ # Any prefix/hacks should be removed from the property name.
34
+ # @param value [String] The value being transformed.
35
+ # @return [String] A new value for the property
36
+ def transform_value(property, value)
37
+ value
38
+ end
39
+
40
+ # It is safe for this method to mutate the expression that is passed to it.
41
+ #
42
+ # @param property [String] The property whose value is being transformed.
43
+ # Any prefix/hacks should be removed from the property name.
44
+ # @param expression [Sass::Script::Node] The value being transformed.
45
+ # @return [Sass::Script::Node] A new expression for the property
46
+ def transform_expression(property, expression)
47
+ return expression
48
+ end
49
+
50
+ protected
51
+
52
+ def opts(options)
53
+ node = yield
54
+ node.options = options
55
+ node
56
+ end
57
+
58
+ def for_each_value(expression)
59
+ if expression.is_a?(Sass::Script::List) && expression.separator == :comma
60
+ expression.value.map! {|e| yield(e) }
61
+ expression
62
+ else
63
+ yield(expression)
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+
@@ -0,0 +1,25 @@
1
+ require 'set'
2
+ module MirrorMirror::Transformation
3
+ class QuadShorthand < PropertyTransformation
4
+ SHORTHAND_PROPERTIES = Set[
5
+ 'border-color',
6
+ 'border-width',
7
+ 'border-style',
8
+ 'margin',
9
+ 'outline',
10
+ 'padding'
11
+ ]
12
+ def transform_expression?(name)
13
+ SHORTHAND_PROPERTIES.include?(name)
14
+ end
15
+
16
+ def transform_expression(name, expression)
17
+ if expression.is_a?(Sass::Script::List) &&
18
+ expression.separator == :space &&
19
+ expression.value.size == 4
20
+ expression.value[1], expression.value[3] = expression.value[3], expression.value[1]
21
+ end
22
+ expression
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ module MirrorMirror::Transformation
2
+ class TextAlign < PropertyTransformation
3
+ def transform_value?(name)
4
+ name == "text-align"
5
+ end
6
+
7
+ def transform_value(name, value)
8
+ case value
9
+ when "left"
10
+ "right"
11
+ when "right"
12
+ "left"
13
+ else
14
+ value
15
+ end
16
+ end
17
+ end
18
+ end
19
+
@@ -0,0 +1,12 @@
1
+ require 'mirror-mirror/transformation/base'
2
+ require 'mirror-mirror/transformation/property_transformation'
3
+ require 'mirror-mirror/transformation/cursor'
4
+ require 'mirror-mirror/transformation/directional_property'
5
+ require 'mirror-mirror/transformation/direction'
6
+ require 'mirror-mirror/transformation/float'
7
+ require 'mirror-mirror/transformation/text_align'
8
+ require 'mirror-mirror/transformation/background_position'
9
+ require 'mirror-mirror/transformation/quad_shorthand'
10
+ require 'mirror-mirror/transformation/box_shadow'
11
+ require 'mirror-mirror/transformation/border_radius'
12
+ require 'mirror-mirror/transformation/linear_gradient'
@@ -1,3 +1,3 @@
1
1
  module MirrorMirror
2
- VERSION = "0.0.1"
2
+ VERSION = "0.9.0"
3
3
  end
data/lib/mirror-mirror.rb CHANGED
@@ -1,5 +1,30 @@
1
+ require 'sass'
1
2
  require "mirror-mirror/version"
3
+ require "mirror-mirror/sass_patch"
2
4
 
3
5
  module MirrorMirror
6
+ class << self
7
+ def activate!
8
+ require 'mirror-mirror/sass_functions'
9
+ add_to_load_path!
10
+ Sass::Tree::RootNode.send(:include, SassPatch)
11
+ Sass::Tree::Visitors::Cssize.send(:include, CssizePatch)
12
+ Sass::Tree::DirectiveNode.send(:include, DirectiveNodePatch)
13
+ end
4
14
 
15
+ def add_to_load_path!
16
+ stylesheets_path = File.expand_path(File.join(File.dirname(__FILE__), '..', 'stylesheets'))
17
+ begin
18
+ require 'compass'
19
+ Compass::Frameworks.register('mirror-mirror', :stylesheets_directory => stylesheets_path)
20
+ rescue LoadError
21
+ # compass not found, register on the Sass path via the environment.
22
+ if ENV.has_key?("SASS_PATH")
23
+ ENV["SASS_PATH"] = ENV["SASS_PATH"] + File::PATH_SEPARATOR + stylesheets_path
24
+ else
25
+ ENV["SASS_PATH"] = stylesheets_path
26
+ end
27
+ end
28
+ end
29
+ end
5
30
  end
@@ -0,0 +1,68 @@
1
+ $mirror-mirror-enabled: mirror-mirror-enabled-by-default() !default;
2
+ $mirror-mirror-noflip: false !default;
3
+ $mirror-mirror-default-inline-context: "*[dir=rtl]" !default;
4
+ $mirror-mirror-inline-contexts: ();
5
+
6
+ @function mm-car($list) {
7
+ $new-list: ();
8
+ @for $i from 1 to length($list) {
9
+ $new-list: append($new-list, nth($list, $i));
10
+ }
11
+ @return $new-list;
12
+ }
13
+
14
+ @mixin enable-mirror-flip {
15
+ @if $mirror-mirror-noflip {
16
+ @warn "Enabled flipping in a no-flip. Ignoring.";
17
+ } @else {
18
+ $mirror-mirror-enabled: true;
19
+ @-mirror-mirror {
20
+ enabled: true;
21
+ @content;
22
+ }
23
+ }
24
+ }
25
+
26
+ @mixin disable-mirror-flip {
27
+ @if $mirror-mirror-noflip {
28
+ @warn "Disabled flipping in a no-flip. Ignoring.";
29
+ } @else {
30
+ $mirror-mirror-enabled: false;
31
+ @-mirror-mirror {
32
+ enabled: false;
33
+ @content;
34
+ }
35
+ }
36
+ }
37
+
38
+ @mixin no-flip {
39
+ @if $mirror-mirror-noflip or not $mirror-mirror-enabled {
40
+ @content;
41
+ } @else {
42
+ $mirror-mirror-noflip: true;
43
+ @-mirror-mirror no-flip {
44
+ @content;
45
+ }
46
+ $mirror-mirror-noflip: false;
47
+ }
48
+ }
49
+
50
+ @mixin inline-flip($selector-context: $mirror-mirror-default-inline-context,
51
+ $prepend-context: false) {
52
+ @if $mirror-mirror-enabled {
53
+ // Do nothing if we're in a flipped context already.
54
+ @content;
55
+ } @else {
56
+ @content;
57
+ @-mirror-mirror inline-flip {
58
+ @if not index($mirror-mirror-inline-contexts, $selector-context) {
59
+ $mirror-mirror-inline-contexts: append($mirror-mirror-inline-contexts, $selector-context);
60
+ #{$selector-context} #{if($prepend-context, '&', null)} {
61
+ @content;
62
+ }
63
+ $mirror-mirror-inline-contexts: mm-car($mirror-mirror-inline-contexts);
64
+ }
65
+ }
66
+ }
67
+ }
68
+
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mirror-mirror
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Eppstein
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-21 00:00:00.000000000 Z
11
+ date: 2014-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sass
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -46,13 +60,28 @@ extensions: []
46
60
  extra_rdoc_files: []
47
61
  files:
48
62
  - .gitignore
49
- - Gemfile
50
63
  - LICENSE.txt
51
64
  - README.md
52
- - Rakefile
53
65
  - lib/mirror-mirror.rb
66
+ - lib/mirror-mirror/activate.rb
67
+ - lib/mirror-mirror/mirror_visitor.rb
68
+ - lib/mirror-mirror/sass_functions.rb
69
+ - lib/mirror-mirror/sass_patch.rb
70
+ - lib/mirror-mirror/transformation.rb
71
+ - lib/mirror-mirror/transformation/background_position.rb
72
+ - lib/mirror-mirror/transformation/base.rb
73
+ - lib/mirror-mirror/transformation/border_radius.rb
74
+ - lib/mirror-mirror/transformation/box_shadow.rb
75
+ - lib/mirror-mirror/transformation/cursor.rb
76
+ - lib/mirror-mirror/transformation/direction.rb
77
+ - lib/mirror-mirror/transformation/directional_property.rb
78
+ - lib/mirror-mirror/transformation/float.rb
79
+ - lib/mirror-mirror/transformation/linear_gradient.rb
80
+ - lib/mirror-mirror/transformation/property_transformation.rb
81
+ - lib/mirror-mirror/transformation/quad_shorthand.rb
82
+ - lib/mirror-mirror/transformation/text_align.rb
54
83
  - lib/mirror-mirror/version.rb
55
- - mirror-mirror.gemspec
84
+ - stylesheets/mirror-mirror.scss
56
85
  homepage: ''
57
86
  licenses:
58
87
  - MIT
@@ -78,4 +107,3 @@ signing_key:
78
107
  specification_version: 4
79
108
  summary: Bidirectional CSS transformation utility for Sass.
80
109
  test_files: []
81
- has_rdoc:
data/Gemfile DELETED
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in mirror-mirror.gemspec
4
- gemspec
data/Rakefile DELETED
@@ -1 +0,0 @@
1
- require "bundler/gem_tasks"
@@ -1,23 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'mirror-mirror/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "mirror-mirror"
8
- spec.version = MirrorMirror::VERSION
9
- spec.authors = ["Chris Eppstein"]
10
- spec.email = ["chris@eppsteins.net"]
11
- spec.description = %q{Flip the design of your website along the vertical axis.}
12
- spec.summary = %q{Bidirectional CSS transformation utility for Sass.}
13
- spec.homepage = ""
14
- spec.license = "MIT"
15
-
16
- spec.files = `git ls-files`.split($/)
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
20
-
21
- spec.add_development_dependency "bundler", "~> 1.3"
22
- spec.add_development_dependency "rake"
23
- end