crass 0.0.1 → 0.0.2

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.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Y2NmZWM1MTg3MjVmNjcxN2ZjN2JhZmE4YzU0NjUxYWFjMDI0MjQwMA==
5
+ data.tar.gz: !binary |-
6
+ NmZmMGJmM2JkYmRiY2JhYjI2N2E1NzVhNDFjNzc3ZjJiZDViNzg3ZQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ ZjRkYzI5Zjk1NGZlOTEzOGI2YTRmMThhMTdiYzNjNDYyNGU4NzhiMjExYTY4
10
+ NDQ4ZDJlYjlhYTBiNTE0OTcwNTk4ZTgxM2VjNGNkMmVkNjgwYzcwNmZiZGRh
11
+ MDM5OWE4YzM3NWIwZjhkN2VhODVlZmJkMDYzMGJjMjgyM2NkNjY=
12
+ data.tar.gz: !binary |-
13
+ ZmMyOWZiNWNkYmQ5OGE3MGFkOWEyMWJiY2JmODYwM2Y0MTRhNzhhZWM1NGE0
14
+ NTU2NTI1MGYyNzVlZDE3ZTZmYWQ4NjkyMmY2NWU4NDA4NGNlNDAyOWIxYWY4
15
+ NmEzNmVkYjYyNTNhMjkwODFkMDU2MmMzOGJkNGZlM2RlYmMwY2E=
@@ -0,0 +1,4 @@
1
+ .yardoc/
2
+ doc/
3
+ .DS_Store
4
+ Gemfile.lock
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - 2.0.0
@@ -0,0 +1 @@
1
+ --markup markdown
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/HISTORY.md CHANGED
@@ -1,4 +1,14 @@
1
1
  Crass Change History
2
2
  ====================
3
3
 
4
- ?????
4
+ 0.0.2 (2013-09-30)
5
+ ------------------
6
+
7
+ * Fixed: `:at_rule` nodes now have a `:name` key.
8
+
9
+
10
+ 0.0.1 (2013-09-27)
11
+ ------------------
12
+
13
+ * Initial release.
14
+
data/README.md CHANGED
@@ -6,6 +6,8 @@ Crass is a Ruby CSS parser based on the [CSS Syntax Module Level 3][css] draft.
6
6
  * [Home](https://github.com/rgrove/crass/)
7
7
  * [API Docs](http://rubydoc.info/github/rgrove/crass/master)
8
8
 
9
+ [![Build Status](https://travis-ci.org/rgrove/crass.png?branch=master)](https://travis-ci.org/rgrove/crass?branch=master)
10
+
9
11
  Features
10
12
  --------
11
13
 
@@ -41,15 +43,19 @@ Problems
41
43
  (except for wholesale removal of nodes) are not reflected in the serialized
42
44
  output.
43
45
 
44
- * It doesn't have any unit tests yet, because it's very, very new and I'm
45
- still experimenting with its architecture.
46
+ * Unit tests aren't complete yet.
46
47
 
47
- * Probably plenty of other things. Did I mention it's very new?
48
+ * Probably tons of other things. Did I mention it's very new and experimental?
48
49
 
49
50
  Installing
50
51
  ----------
51
52
 
52
- Don't install it yet. It's not finished.
53
+ ```
54
+ gem install crass
55
+ ```
56
+
57
+ ...but only if you're brave. Seriously, this thing will almost certainly kill
58
+ your family and poop on your pets.
53
59
 
54
60
  Examples
55
61
  --------
@@ -134,6 +140,34 @@ a:hover {
134
140
 
135
141
  Wasn't that exciting?
136
142
 
143
+ A Note on Versioning
144
+ --------------------
145
+
146
+ Crass's version number currently has a "0.x" prefix, indicating that it's a new
147
+ project under heavy development. **As long as the version number starts with
148
+ "0.x", minor revisions may introduce breaking changes.** You've been warned!
149
+
150
+ Once Crass reaches version 1.0.0, it will adhere strictly to
151
+ [SemVer 2.0][semver].
152
+
153
+ [semver]:http://semver.org/spec/v2.0.0.html
154
+
155
+ Contributing
156
+ ------------
157
+
158
+ The best way to contribute right now is to use Crass and [create issues][issue]
159
+ when you run into problems.
160
+
161
+ Pull requests that fix bugs are more than welcome as long as they include tests.
162
+ Please adhere to the style and format of the surrounding code, or I might ask
163
+ you to change things.
164
+
165
+ If you want to add a feature or refactor something, please get in touch first to
166
+ make sure I'm on board with your idea and approach; I'm pretty picky, and I'd
167
+ hate to have to turn down a pull request you spent a lot of time on.
168
+
169
+ [issue]: https://github.com/rgrove/crass/issues/new
170
+
137
171
  License
138
172
  -------
139
173
 
@@ -0,0 +1,7 @@
1
+ require 'bundler'
2
+ require 'rake/testtask'
3
+
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ Rake::TestTask.new
7
+ task :default => [:test]
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+ require './lib/crass/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'crass'
6
+ s.summary = 'CSS parser based on the CSS Syntax Module Level 3 draft.'
7
+ s.description = 'Crass is a pure Ruby CSS parser based on the CSS Syntax Module Level 3 draft.'
8
+ s.version = Crass::VERSION
9
+ s.authors = ['Ryan Grove']
10
+ s.email = ['ryan@wonko.com']
11
+ s.homepage = 'https://github.com/rgrove/crass/'
12
+ s.license = 'MIT'
13
+
14
+ s.platform = Gem::Platform::RUBY
15
+ s.required_ruby_version = Gem::Requirement.new('>= 1.9.2')
16
+
17
+ s.require_paths = ['lib']
18
+
19
+ s.files = `git ls-files`.split($/)
20
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
21
+
22
+ # Development dependencies.
23
+ s.add_development_dependency 'minitest', '~> 5.0.8'
24
+ s.add_development_dependency 'rake', '~> 10.1.0'
25
+ end
@@ -10,4 +10,5 @@ module Crass
10
10
  def self.parse(input, options = {})
11
11
  Parser.parse_stylesheet(input, options)
12
12
  end
13
+
13
14
  end
@@ -28,7 +28,7 @@ module Crass
28
28
  rules.map do |rule|
29
29
  case rule[:node]
30
30
  # TODO: handle at-rules
31
- when :qualified_rule then parser.parse_style_rule(rule)
31
+ when :qualified_rule then parser.create_style_rule(rule)
32
32
  else rule
33
33
  end
34
34
  end
@@ -91,29 +91,33 @@ module Crass
91
91
 
92
92
  # Consumes an at-rule and returns it.
93
93
  #
94
- # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-an-at-rule0
95
- def consume_at_rule(tokens = @tokens)
96
- rule = {:prelude => []}
94
+ # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-an-at-rule
95
+ def consume_at_rule(input = @tokens)
96
+ rule = {}
97
+
98
+ rule[:tokens] = input.collect do
99
+ rule[:name] = parse_value(input.consume)
100
+ rule[:prelude] = []
97
101
 
98
- rule[:tokens] = tokens.collect do
99
- while token = tokens.consume
102
+ while token = input.consume
100
103
  case token[:node]
101
104
  when :comment then next
102
105
  when :semicolon, :eof then break
103
106
 
104
107
  when :'{' then
105
- rule[:block] = consume_simple_block(tokens)
108
+ rule[:block] = consume_simple_block(input)
106
109
  break
107
110
 
108
- # TODO: At this point, the spec says we should check for a "simple block
109
- # with an associated token of <<{-token>>", but isn't that exactly what
110
- # we just did above? And the tokenizer only ever produces standalone
111
- # <<{-token>>s, so how could the token stream ever contain one that's
112
- # already associated with a simple block? What am I missing?
111
+ # TODO: At this point, the spec says we should check for a "simple
112
+ # block with an associated token of <<{-token>>", but isn't that
113
+ # exactly what we just did above? And the tokenizer only ever produces
114
+ # standalone <<{-token>>s, so how could the token stream ever contain
115
+ # one that's already associated with a simple block? What am I
116
+ # missing?
113
117
 
114
118
  else
115
- tokens.reconsume
116
- rule[:prelude] << consume_component_value(tokens)
119
+ input.reconsume
120
+ rule[:prelude] << consume_component_value(input)
117
121
  end
118
122
  end
119
123
  end
@@ -124,12 +128,12 @@ module Crass
124
128
  # Consumes a component value and returns it.
125
129
  #
126
130
  # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-component-value0
127
- def consume_component_value(tokens = @tokens)
128
- return nil unless token = tokens.consume
131
+ def consume_component_value(input = @tokens)
132
+ return nil unless token = input.consume
129
133
 
130
134
  case token[:node]
131
- when :'{', :'[', :'(' then consume_simple_block(tokens)
132
- when :function then consume_function(tokens)
135
+ when :'{', :'[', :'(' then consume_simple_block(input)
136
+ when :function then consume_function(input)
133
137
  else token
134
138
  end
135
139
  end
@@ -137,19 +141,19 @@ module Crass
137
141
  # Consumes a declaration and returns it, or `nil` on parse error.
138
142
  #
139
143
  # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-declaration0
140
- def consume_declaration(tokens = @tokens)
144
+ def consume_declaration(input = @tokens)
141
145
  declaration = {}
142
146
 
143
- declaration[:tokens] = tokens.collect do
144
- declaration[:name] = tokens.consume[:value]
147
+ declaration[:tokens] = input.collect do
148
+ declaration[:name] = input.consume[:value]
145
149
 
146
150
  value = []
147
- token = tokens.consume
148
- token = tokens.consume while token[:node] == :whitespace
151
+ token = input.consume
152
+ token = input.consume while token[:node] == :whitespace
149
153
 
150
154
  return nil if token[:node] != :colon # TODO: parse error
151
155
 
152
- value << token while token = tokens.consume
156
+ value << token while token = input.consume
153
157
  declaration[:value] = value
154
158
 
155
159
  maybe_important = value.reject {|v| v[:node] == :whitespace }[-2, 2]
@@ -173,10 +177,10 @@ module Crass
173
177
  # `:whitespace` nodes, which is non-standard.
174
178
  #
175
179
  # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-list-of-declarations0
176
- def consume_declarations(tokens = @tokens)
180
+ def consume_declarations(input = @tokens)
177
181
  declarations = []
178
182
 
179
- while token = tokens.consume
183
+ while token = input.consume
180
184
  case token[:node]
181
185
  when :comment, :semicolon, :whitespace
182
186
  declarations << token
@@ -184,16 +188,19 @@ module Crass
184
188
  when :at_keyword
185
189
  # TODO: this is technically a parse error when parsing a style rule,
186
190
  # but not necessarily at other times.
187
- declarations << consume_at_rule(tokens)
191
+
192
+ # TODO: It seems like we should reconsume the current token here,
193
+ # since that's what happens when consuming a list of rules.
194
+ declarations << consume_at_rule(input)
188
195
 
189
196
  when :ident
190
197
  decl_tokens = [token]
191
- tokens.consume
198
+ input.consume
192
199
 
193
- while tokens.current
194
- decl_tokens << tokens.current
195
- break if tokens.current[:node] == :semicolon
196
- tokens.consume
200
+ while input.current
201
+ decl_tokens << input.current
202
+ break if input.current[:node] == :semicolon
203
+ input.consume
197
204
  end
198
205
 
199
206
  if decl = consume_declaration(TokenScanner.new(decl_tokens))
@@ -203,7 +210,7 @@ module Crass
203
210
  else
204
211
  # TODO: parse error (invalid property name, etc.)
205
212
  while token && token[:node] != :semicolon
206
- token = consume_component_value(tokens)
213
+ token = consume_component_value(input)
207
214
  end
208
215
  end
209
216
  end
@@ -214,22 +221,22 @@ module Crass
214
221
  # Consumes a function and returns it.
215
222
  #
216
223
  # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-function
217
- def consume_function(tokens = @tokens)
224
+ def consume_function(input = @tokens)
218
225
  function = {
219
- :name => tokens.current[:value],
226
+ :name => input.current[:value],
220
227
  :value => [],
221
- :tokens => [tokens.current]
228
+ :tokens => [input.current]
222
229
  }
223
230
 
224
- function[:tokens].concat(tokens.collect do
225
- while token = tokens.consume
231
+ function[:tokens].concat(input.collect do
232
+ while token = input.consume
226
233
  case token[:node]
227
234
  when :')', :eof then break
228
235
  when :comment then next
229
236
 
230
237
  else
231
- tokens.reconsume
232
- function[:value] << consume_component_value(tokens)
238
+ input.reconsume
239
+ function[:value] << consume_component_value(input)
233
240
  end
234
241
  end
235
242
  end)
@@ -241,15 +248,15 @@ module Crass
241
248
  # occurs.
242
249
  #
243
250
  # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-qualified-rule0
244
- def consume_qualified_rule(tokens = @tokens)
251
+ def consume_qualified_rule(input = @tokens)
245
252
  rule = {:prelude => []}
246
253
 
247
- rule[:tokens] = tokens.collect do
254
+ rule[:tokens] = input.collect do
248
255
  while true
249
- return nil unless token = tokens.consume
256
+ return nil unless token = input.consume
250
257
 
251
258
  if token[:node] == :'{'
252
- rule[:block] = consume_simple_block(tokens)
259
+ rule[:block] = consume_simple_block(input)
253
260
  break
254
261
 
255
262
  # elsif [simple block with an associated <<{-token>>??]
@@ -261,8 +268,8 @@ module Crass
261
268
  # already associated with a simple block? What am I missing?
262
269
 
263
270
  else
264
- tokens.reconsume
265
- rule[:prelude] << consume_component_value(tokens)
271
+ input.reconsume
272
+ rule[:prelude] << consume_component_value(input)
266
273
  end
267
274
  end
268
275
  end
@@ -307,23 +314,23 @@ module Crass
307
314
  # token.
308
315
  #
309
316
  # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-simple-block0
310
- def consume_simple_block(tokens = @tokens)
311
- start_token = tokens.current[:node]
317
+ def consume_simple_block(input = @tokens)
318
+ start_token = input.current[:node]
312
319
  end_token = BLOCK_END_TOKENS[start_token]
313
320
 
314
321
  block = {
315
322
  :start => start_token.to_s,
316
323
  :end => end_token.to_s,
317
324
  :value => [],
318
- :tokens => [tokens.current]
325
+ :tokens => [input.current]
319
326
  }
320
327
 
321
- block[:tokens].concat(tokens.collect do
322
- while token = tokens.consume
328
+ block[:tokens].concat(input.collect do
329
+ while token = input.consume
323
330
  break if token[:node] == end_token || token[:node] == :eof
324
331
 
325
- tokens.reconsume
326
- block[:value] << consume_component_value(tokens)
332
+ input.reconsume
333
+ block[:value] << consume_component_value(input)
327
334
  end
328
335
  end)
329
336
 
@@ -335,21 +342,22 @@ module Crass
335
342
  {:node => type}.merge!(properties)
336
343
  end
337
344
 
338
- # Parses the given _tokens_ into a selector node and returns it.
345
+ # Parses the given _input_ tokens into a selector node and returns it.
339
346
  #
340
347
  # Doesn't bother splitting the selector list into individual selectors or
341
348
  # validating them. Feel free to do that yourself! It'll be fun!
342
- def parse_selector(tokens)
349
+ def create_selector(input)
343
350
  create_node(:selector,
344
- :value => parse_value(tokens),
345
- :tokens => tokens)
351
+ :value => parse_value(input),
352
+ :tokens => input)
346
353
  end
347
354
 
348
- # Parses a style rule and returns the result.
355
+ # Creates a `:style_rule` node from the given qualified _rule_, and returns
356
+ # it.
349
357
  #
350
- # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#style-rules
351
- # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-list-of-declarations0
352
- def parse_style_rule(rule)
358
+ # * http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#style-rules
359
+ # * http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-list-of-declarations0
360
+ def create_style_rule(rule)
353
361
  children = []
354
362
  tokens = TokenScanner.new(rule[:block][:value])
355
363
 
@@ -366,7 +374,7 @@ module Crass
366
374
  end
367
375
 
368
376
  create_node(:style_rule,
369
- :selector => parse_selector(rule[:prelude]),
377
+ :selector => create_selector(rule[:prelude]),
370
378
  :children => children
371
379
  )
372
380
  end
@@ -375,10 +383,14 @@ module Crass
375
383
  def parse_value(nodes)
376
384
  string = ''
377
385
 
386
+ nodes = [nodes] unless nodes.is_a?(Array)
387
+
378
388
  nodes.each do |node|
379
389
  case node[:node]
380
390
  when :comment, :semicolon then next
381
- when :ident then string << node[:value]
391
+
392
+ when :at_keyword, :ident
393
+ string << node[:value]
382
394
 
383
395
  when :function
384
396
  if node[:value].is_a?(String)