crass 0.0.1 → 0.0.2

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