Class: CssCompare::CSS::Engine
- Inherits:
-
Object
- Object
- CssCompare::CSS::Engine
- Includes:
- Component
- Defined in:
- lib/css_compare/css/engine.rb
Overview
The CSS Engine that computes the values of the properties under all the declared parent_query_list in the stylesheet.
It can handle:
- simple property overriding
- property overriding with !import
- @import rules
- @media queries - PARTIAL SUPPORT ONLY!!!
- nested @media queries also know as nested conditional
group rules
- @keyframes rules
- @namespace rules
- @charset rules
- @page rules
- @supports rules
However, the @media and @supports evaluations are not 100% reliable, since the parent_query_list of each directive are not interpreted and evaluated by the engine. Instead, they are stringified as a whole and used as the key for their selector-property pairs.
“When multiple conditional group rules are nested, a rule inside of both of them applies only when all of the rules’ parent_query_list are true.” The imports are dynamically loaded and evaluated with the root document together. The result shows the final values of each CSS properties and rules, just like a browser would interpret the linked CSS stylesheets.
Constant Summary collapse
- GLOBAL_QUERY =
'all'.freeze
Instance Attribute Summary collapse
-
#charset ⇒ Object
Returns the value of attribute charset.
-
#engine ⇒ Hash<Symbol, Array<Component::Selector, String>]
The inner representation of the computed properties of each selector under every condition specified by the declared @media directives.
-
#keyframes ⇒ Object
Returns the value of attribute keyframes.
-
#namespaces ⇒ Object
Returns the value of attribute namespaces.
-
#pages ⇒ Object
Returns the value of attribute pages.
-
#selectors ⇒ Object
Returns the value of attribute selectors.
-
#supports ⇒ Object
Returns the value of attribute supports.
-
#unsupported ⇒ Array<Sass::Tree::Node>
A list of nodes, that could not be evaluated due to being not supported by this engine.
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
Checks, whether two engines are equal.
-
#deep_copy ⇒ Engine
Creates a deep copy of this object.
-
#evaluate(tree = @tree, parent_query_list = []) ⇒ Void
Computes the values of each declared selector’s properties under each condition declared by the @media directives.
-
#initialize(input) ⇒ Engine
constructor
A new instance of Engine.
-
#to_json ⇒ Hash
Returns the inner representation of the processed CSS stylesheet.
Methods included from Component
Constructor Details
#initialize(input) ⇒ Engine
UTF-8 is assumed as default charset
Returns a new instance of Engine.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/css_compare/css/engine.rb', line 62 def initialize(input) @tree = begin if input.is_a?(String) Parser.new(input).parse.freeze elsif input.is_a?(Sass::Tree::Node) input.freeze else raise ArgumentError, "The engine's input must be either a path, or a Sass::Tree::Node" end end @filename = @tree.[:filename] @engine = {} @selectors = {} @font_faces = {} @keyframes = {} @namespaces = {} @pages = {} @supports = {} @unsupported = [] @charset = 'UTF-8' end |
Instance Attribute Details
#charset ⇒ Object
Returns the value of attribute charset.
54 55 56 |
# File 'lib/css_compare/css/engine.rb', line 54 def charset @charset end |
#engine ⇒ Hash<Symbol, Array<Component::Selector, String>]
The inner representation of the computed properties of each selector under every condition specified by the declared @media directives.
46 47 48 |
# File 'lib/css_compare/css/engine.rb', line 46 def engine @engine end |
#keyframes ⇒ Object
Returns the value of attribute keyframes.
54 55 56 |
# File 'lib/css_compare/css/engine.rb', line 54 def keyframes @keyframes end |
#namespaces ⇒ Object
Returns the value of attribute namespaces.
54 55 56 |
# File 'lib/css_compare/css/engine.rb', line 54 def namespaces @namespaces end |
#pages ⇒ Object
Returns the value of attribute pages.
54 55 56 |
# File 'lib/css_compare/css/engine.rb', line 54 def pages @pages end |
#selectors ⇒ Object
Returns the value of attribute selectors.
54 55 56 |
# File 'lib/css_compare/css/engine.rb', line 54 def selectors @selectors end |
#supports ⇒ Object
Returns the value of attribute supports.
54 55 56 |
# File 'lib/css_compare/css/engine.rb', line 54 def supports @supports end |
#unsupported ⇒ Array<Sass::Tree::Node>
A list of nodes, that could not be evaluated due to being not supported by this engine.
52 53 54 |
# File 'lib/css_compare/css/engine.rb', line 52 def unsupported @unsupported end |
Instance Method Details
#==(other) ⇒ Boolean
Checks, whether two engines are equal.
They are equal only if the same symbols are defined and each and every component under those keys are also equal.
93 94 95 96 |
# File 'lib/css_compare/css/engine.rb', line 93 def ==(other) keys = @engine.keys keys.all? { |key| @engine[key] == other.engine[key] } end |
#deep_copy ⇒ Engine
Creates a deep copy of this object.
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/css_compare/css/engine.rb', line 190 def deep_copy copy = dup copy.selectors = @selectors.inject({}) do |result, (k, v)| result.update(k => v.deep_copy) end copy.keyframes = @keyframes.inject({}) do |result, (k, v)| result.update(k => v.deep_copy) end copy.pages = @supports.inject({}) do |result, (k, v)| result.update(k => v.deep_copy) end copy.supports = @supports.inject({}) do |result, (k, v)| result.update(k => v.deep_copy) end copy.engine = { :selectors => copy.selectors, :keyframes => copy.keyframes, :namespaces => copy.namespaces, :pages => copy.pages, :supports => copy.supports } copy end |
#evaluate(tree = @tree, parent_query_list = []) ⇒ Void
the second parameter has been added to ensure multiply nested @media, @support and @import rules.
Computes the values of each declared selector’s properties under each condition declared by the @media directives.
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/css_compare/css/engine.rb', line 110 def evaluate(tree = @tree, parent_query_list = []) tree = @tree unless tree # if nil is passed explicitly tree.children.each do |node| if node.is_a?(Sass::Tree::MediaNode) process_media_node(node, parent_query_list) elsif node.is_a?(Sass::Tree::RuleNode) process_rule_node(node, parent_query_list) elsif node.is_a?(Sass::Tree::DirectiveNode) if node.is_a?(Sass::Tree::SupportsNode) process_supports_node(node) elsif node.is_a?(Sass::Tree::CssImportNode) process_import_node(node, parent_query_list) else begin case node.name when '@keyframes' process_keyframes_node(node, parent_query_list) when '@namespace' process_namespace_node(node) when '@page' process_page_node(node, parent_query_list) when '@font-face' process_font_face_node(node, parent_query_list) else # Unsupported DirectiveNodes, that have a name property @unsupported << node end rescue NotImplementedError # Unsupported DirectiveNodes, that do not implement a name getter @unsupported << node end end elsif node.is_a?(Sass::Tree::CharsetNode) process_charset_node(node) else # Unsupported Node @unsupported << node end end @engine[:selectors] = @selectors @engine[:font_faces] = @font_faces @engine[:keyframes] = @keyframes @engine[:namespaces] = @namespaces @engine[:pages] = @pages @engine[:supports] = @supports @engine[:charset] = @charset self end |
#to_json ⇒ Hash
Returns the inner representation of the processed CSS stylesheet.
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/css_compare/css/engine.rb', line 163 def to_json engine = { :selectors => [], :font_faces => {}, :keyframes => [], :namespaces => @namespaces, :pages => [], :supports => [], :charset => @charset } @selectors.inject(engine[:selectors]) { |arr, (_, s)| arr << s.to_json } @font_faces.each_with_object(engine[:font_faces]) do |(cond, font_families), arr| arr[cond] = font_families.inject([]) do |font_faces, (_, font_family)| font_faces + font_family.inject([]) do |sum, (_, font_face)| sum << font_face.to_json end end end @keyframes.inject(engine[:keyframes]) { |arr, (_, k)| arr << k.to_json } @pages.inject(engine[:pages]) { |arr, (_, p)| arr << p.to_json } @supports.inject(engine[:supports]) { |arr, (_, s)| arr << s.to_json } engine end |