Skip to content

Commit

Permalink
add Rule.from_string() and Rule.to_string()
Browse files Browse the repository at this point in the history
  • Loading branch information
drscannellrh committed Apr 6, 2014
1 parent a77d999 commit 97f0018
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 0 deletions.
35 changes: 35 additions & 0 deletions readme.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ This is a a CSS modeling utility written in pure Python.
## Usage ##

```python
from css_parser.stylesheet import StyleSheet

# parse css string
text = 'body {margin:0;} p.indent{text-indent:1em;}'
stylesheet = StyleSheet.from_string(text)
Expand Down Expand Up @@ -43,12 +45,44 @@ stylesheet.prepend_rule(newrule, existingrule)
mediaquery = existingrule.get_mediaquery()
newrule.set_mediaquery(mediaquery)
stylesheet.append(newrule, mediaquery)

'''
If the media-queries don't match, the new rule
will be added before/after the media-query,
depending on whether prepend_rule or
append_rule is used.
'''

from css_parser.rule import Rule

# create rule from string
text = 'blockquote {margin:1em 5% 1em 5%;}'
rule = Rule.from_string(text)

# media-queries are retained
text = '@media all {blockquote {margin:1em 5% 1em 5%;} }'
rule = Rule.from_string(text)

# multiple rules can be generated in this way, if desired
text = '/* multiple rules */' \
'@media all {' \
' blockquote {' \
' margin:1em 5% 1em 5%;' \
' }' \
' p {' \
' color:blue;' \
' }' \
'}'
rule = Rule.from_string(text)

'''
Note: If it is important that comments and whitespace be
preserved, use StyleSheet.from_string() rather than Rule.from_string().
'''

# write single rule to string
# includes media-query, if applicable
rule.to_string()
```

## Features
Expand All @@ -71,6 +105,7 @@ append_rule is used.

### Rule

1. [ ] Create Rule from string
1. [ ] Get declarations by property
2. [ ] Append declaration
3. [ ] Prepend declaration
Expand Down
19 changes: 19 additions & 0 deletions src/css_parser/rule.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
import re
import stylesheet_reader

class Rule:
def __init__(self, tokens=[]):
self.tokens = tokens
self.selector_tokens = []
self.declarations = []
self.mediaquery = None

@classmethod
def from_string(cls, text):
stylesheet = stylesheet_reader.StyleSheetReader.read_string(text)
if len(stylesheet.get_rules()) == 1:
return stylesheet.get_rules()[0]
if len(stylesheet.get_rules()) > 1:
return stylesheet.get_rules()
return None

def set_selector_tokens(self, tokens):
self.selector_tokens = tokens
Expand All @@ -32,3 +42,12 @@ def stringify_tokens(self, tokens):
txt = ''.join([str(t) for t in tokens])
return re.sub('\s+', ' ', txt).strip()

def to_string(self):
tokens = [t for t in self.tokens]
if self.mediaquery:
m = self.mediaquery
tokens = m.get_starttokens() + tokens + m.get_endtokens()
return ''.join([str(t) for t in tokens])

def __str__(self):
return ''.join([str(t) for t in self.tokens])
82 changes: 82 additions & 0 deletions src/tests/test_rule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import os
import re
from css_parser.stylesheet import StyleSheet
from css_parser.rule import Rule

class TestCases:

# ----------------------------------------

def test_from_string(self):
tests = [
# one rule
{'input': 'body{margin:0;}',
'expected': 'body{margin:0;}'
},
# one rule, space around
{'input': ' p.indent {margin:0;} ',
'expected': 'p.indent {margin:0;}'
},
# one rule, multilined
{'input': 'p.indent {' \
' margin:0;' \
'}',
'expected': 'p.indent {' \
' margin:0;' \
'}'
},
# one rule, media-queried
{'input': '@media all {' \
' p { margin:0;}' \
'}',
'expected': '@media all {' \
'p { margin:0;}' \
'}'
}

]

for test in tests:
yield self.check_from_string, test

def check_from_string(self, test):
rule = Rule.from_string(test['input'])
observed = rule.to_string()
for k in test:
print '%s: %s' % (k, test[k])
print 'observed: %s' % (observed)
assert observed == test['expected']

# ----------------------------------------

def test_from_string_multiple_rules(self):
tests = [
# two rules
{'input': 'body{margin:0;} p {padding:0 }',
'expected': ['body{margin:0;}', 'p {padding:0 }']
},
# two rules, media-queried
{'input': '@media all {' \
' p { margin:0;}' \
' span { margin:0;}' \
'}',
'expected': ['@media all {p { margin:0;}}',
'@media all {span { margin:0;}}']
}
]

for test in tests:
yield self.check_from_string_multiple_rules, test

def check_from_string_multiple_rules(self, test):
rules = Rule.from_string(test['input'])
observed = [r.to_string() for r in rules]
for k in test:
print '%s: %s' % (k, test[k])
print 'observed: %s' % (observed)
assert observed == test['expected']

# ----------------------------------------



0 comments on commit 97f0018

Please sign in to comment.