Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
drscannellrh committed Apr 13, 2014
2 parents 5688ca3 + a58c721 commit 670f6b0
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 67 deletions.
30 changes: 23 additions & 7 deletions readme.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ This is a a CSS modeling utility written in pure Python.
6. [] Remove rule
7. [] Prepend rule
8. [] Append rule
9. [] Add rule before existing rule
10. [] Add rule after existing rule
11. [ ] Comment out rule
12. [] Add rule to media-query
13. [ ] Add rule with new media-query
9. [] Add rule before/after existing rule
10. [ ] Comment out rule
11. [] Add rule to media-query
12. [ ] Add rule with new media-query
13. [ ] Pretty-Printing

### Rule

Expand All @@ -28,9 +28,10 @@ This is a a CSS modeling utility written in pure Python.
1. [] Get declarations by property
1. [] Remove declaration
2. [] Append declaration
3. [ ] Prepend declaration
4. [ ] Add declaration before/after existing declaration
3. [] Prepend declaration
4. [] Add declaration before/after existing declaration
5. [ ] Comment out declaration
6. [ ] Pretty-Printing



Expand Down Expand Up @@ -145,6 +146,15 @@ rule.remove_declaration(declaration)

# append declaration
rule.append_declaration(declaration)

# insert declaration after existing declaration
rule.append_declaration(declaration, existingdeclaration)

# prepend declaration
rule.append_declaration(declaration)

# insert declaration before existing declaration
rule.prepend_declaration(declaration, existingdeclaration)
```

### Declaration ###
Expand All @@ -155,4 +165,10 @@ from css_parser.rule import Rule
# create declaration from string
text = 'margin:1em 5% 1em 5%;'
declaration = Declaration.from_string(text)

# get property
prop_string = declaration.get_property()

# get value
val_string = declaration.get_value()
```
30 changes: 30 additions & 0 deletions src/css_parser/css_structure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

class CssStructure:

def _insert_tokens_before(self, new, existing):
tokens = new.get_tokens()
firsttoken = existing.get_tokens()[0]
self._insert_tokens_before_token(tokens, firsttoken)

def _insert_tokens_before_token(self, tokens, token):
i = self.tokens.index(token)
for t in reversed(tokens):
self.tokens.insert(i, t)

def _insert_tokens_after(self, new, existing):
tokens = new.get_tokens()
existingtokens = existing.get_tokens()
lasttoken = existingtokens[-1]
self._insert_tokens_after_token(tokens, lasttoken)

def _insert_tokens_after_token(self, tokens, token):
if token == self.tokens[-1]:
self.tokens += tokens
else:
i = self.tokens.index(token) + 1
for t in reversed(tokens):
self.tokens.insert(i, t)

def __str__(self):
return ''.join([str(t) for t in self.tokens])

8 changes: 8 additions & 0 deletions src/css_parser/mediaquery.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ def __init__(self, starttokens=[], endtokens=[], querytext=''):
self.endtokens = endtokens
self.querytext = querytext

def get_tokens(self):
""" get all tokens directly associated with media-query
TODO: This approach leaves me uneasy, as it does not
convey the gap in the middle where rules would be.
"""
return self.get_starttokens() + self.get_endtokens()

def get_starttokens(self):
return self.starttokens

Expand Down
77 changes: 53 additions & 24 deletions src/css_parser/rule.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import css_structure
import re
import stylesheet_reader
import token

class Rule:
class Rule(css_structure.CssStructure):
def __init__(self, tokens=[]):
self.tokens = tokens
self.selector_tokens = []
Expand Down Expand Up @@ -30,50 +32,77 @@ def get_tokens(self):
return self.tokens

def get_selector(self):
return self.stringify_tokens(self.selector_tokens)
txt = ''.join([str(t) for t in self.selector_tokens])
return re.sub('\s+', ' ', txt).strip()

def get_declarations(self, query=None):
if query:
return self._get_declarations_by_query(query)
return self.declarations

def _get_declarations_by_query(self, query):
matches = []
for declaration in self.declarations:
if declaration.get_property().strip() == query.strip():
matches.append(declaration)
return matches

def remove_declaration(self, decl):
i = self.declarations.index(decl)
self.declarations.pop(i)
decl.remove()

def append_declaration(self, newdecl, existingdecl=None):
if existingdecl:
raise Exception('not implemented')
def prepend_declaration(self, new, existing=None):
if existing:
self._insert_decl_before(new, existing)
else:
lastdecl = self.declarations[-1]
lasttoken = lastdecl.get_tokens()[-1]
i = self.tokens.index(lasttoken) + 1
for t in reversed(newdecl.get_tokens()):
self.tokens.insert(i, t)
self.declarations.append(newdecl)
blockstart = self._get_block_start()
self._insert_tokens_after_token(new.get_tokens(), blockstart)
self.declarations.insert(0, new)

def append_declaration(self, new, existing=None):
if existing:
self._insert_decl_after(new, existing)
else:
blockend = self._get_block_end()
self._insert_tokens_before_token(new.get_tokens(), blockend)
self.declarations.append(new)

def _get_block_start(self):
for t in self.get_tokens():
if t.get_type() == token.Token.BLOCK_START:
return t
return None

def _get_block_end(self):
for t in self.get_tokens():
if t.get_type() == token.Token.BLOCK_END:
return t
return None

def get_mediaquery(self):
return self.mediaquery

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])
# ------------- private -------------

def _get_declarations_by_query(self, query):
matches = []
for declaration in self.declarations:
if declaration.get_property().strip() == query.strip():
matches.append(declaration)
return matches

def _insert_decl_before(self, new, existing):
self._insert_tokens_before(new, existing)
i = self.declarations.index(existing)
self.declarations.insert(i, new)

def _insert_decl_after(self, new, existing):
self._insert_tokens_after(new, existing)
i = self.declarations.index(existing)
self.declarations.insert(i, new)





46 changes: 12 additions & 34 deletions src/css_parser/stylesheet.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import css_structure
import re
import stylesheet_reader
import stylesheet_writer

class StyleSheet:
class StyleSheet(css_structure.CssStructure):

def __init__(self):
self.mediaqueries = []
Expand Down Expand Up @@ -67,47 +68,24 @@ def to_string(self):
def to_file(self, filepath):
stylesheet_writer.StyleSheetWriter.write_filepath(self, filepath)

def __str__(self):
return ''.join([str(t) for t in self.tokens])

# ------------- private -------------

def _insert_rule_before(self, newrule, existingrule):
firsttoken = None
if newrule.get_mediaquery() != existingrule.get_mediaquery():
mediaquery = existingrule.get_mediaquery()
firsttoken = mediaquery.get_starttokens()[0]
else:
firsttoken = existingrule.get_tokens()[0]
self._insert_tokens_before(newrule.get_tokens(), firsttoken)
i = self.rules.index(existingrule)
self.rules.insert(i, newrule)
def _insert_rule_before(self, new, existing):
insertbefore = existing
if new.get_mediaquery() != existing.get_mediaquery():
insertbefore = existing.get_mediaquery()
self._insert_tokens_before(new, insertbefore)
i = self.rules.index(existing)
self.rules.insert(i, new)

def _insert_rule_after(self, newrule, existingrule):
lasttoken = None
insertafter = existingrule
if newrule.get_mediaquery() != existingrule.get_mediaquery():
mediaquery = existingrule.get_mediaquery()
lasttoken = mediaquery.get_endtokens()[-1]
else:
existingruletokens = existingrule.get_tokens()
lasttoken = existingruletokens[len(existingruletokens) - 1]
self._insert_tokens_after(newrule.get_tokens(), lasttoken)
insertafter = existingrule.get_mediaquery()
self._insert_tokens_after(newrule, insertafter)
i = self.rules.index(existingrule)
self.rules.insert(i, newrule)

def _insert_tokens_before(self, tokens, token):
i = self.tokens.index(token)
for t in reversed(tokens):
self.tokens.insert(i, t)

def _insert_tokens_after(self, tokens, token):
if token == self.tokens[-1]:
self.tokens += tokens
else:
i = self.tokens.index(token) + 1
for t in reversed(tokens):
self.tokens.insert(i, t)

def _get_rules_by_query(self, query):
query = re.sub(r'\s+', ' ', query)
matches = []
Expand Down
30 changes: 28 additions & 2 deletions src/tests/test_rule/test_append_declaration.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,34 @@ def test_append_declaration(self):
' padding:0;' \
'}',
'to_add': 'color:blue;',
'existing_index': None,
'expected': 'body{' \
' margin:0;' \
' padding:0;color:blue;' \
'}'
},
{'input': 'body{\n' \
' margin:0;\n' \
' padding:0;\n' \
'}',
'to_add': 'color:blue;',
'existing_index': None,
'expected': 'body{\n' \
' margin:0;\n' \
' padding:0;\n' \
'color:blue;}'
},
{'input': 'body{' \
' margin:0;' \
' padding:0;' \
'}',
'to_add': 'color:blue;',
'existing_index': 0,
'expected': 'body{' \
' margin:0;color:blue;' \
' padding:0;' \
'}'
}

]

for test in tests:
Expand All @@ -27,7 +49,10 @@ def test_append_declaration(self):
def check_append_declaration(self, test):
rule = Rule.from_string(test['input'])
decl = Declaration.from_string(test['to_add'])
rule.append_declaration(decl)
existing_rule = None
if test['existing_index'] != None:
existing_rule = rule.declarations[test['existing_index']]
rule.append_declaration(decl, existing_rule)
observed = rule.to_string()
for k in test:
print '%s: %s' % (k, test[k])
Expand All @@ -38,3 +63,4 @@ def check_append_declaration(self, test):




56 changes: 56 additions & 0 deletions src/tests/test_rule/test_prepend_declaration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from css_parser.rule import Rule
from css_parser.declaration import Declaration

class TestCases:

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

def test_prepend_declaration(self):
tests = [
# two declarations, add one
{'input': 'body{' \
' margin:0;' \
' padding:0;' \
'}',
'to_add': 'color:blue;',
'existing_index': None,
'expected': 'body{color:blue;' \
' margin:0;' \
' padding:0;' \
'}'
},
{'input': 'body{' \
' margin:0;' \
' padding:0;' \
'}',
'to_add': 'color:blue;',
'existing_index': 0,
'expected': 'body{' \
' color:blue;margin:0;' \
' padding:0;' \
'}'
}
]

for test in tests:
yield self.check_prepend_declaration, test

def check_prepend_declaration(self, test):
rule = Rule.from_string(test['input'])
decl = Declaration.from_string(test['to_add'])
existing_rule = None
if test['existing_index'] != None:
existing_rule = rule.declarations[test['existing_index']]
rule.prepend_declaration(decl, existing_rule)
observed = rule.to_string()
for k in test:
print '%s: %s' % (k, test[k])
print 'observed: %s' % (observed)
assert observed == test['expected']

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





0 comments on commit 670f6b0

Please sign in to comment.