Skip to content

Commit

Permalink
Compare Xcode colors up to 4 decimal places (lyft#51)
Browse files Browse the repository at this point in the history
Xcode formats the floats different in different circumstances. To avoid churn and false positives, only compare the first 4 places of color decimals. This avoids linter errors when the color is inappreciably different.
  • Loading branch information
soffes authored and Ilya Konstantinov committed Oct 11, 2019
1 parent f9f70f8 commit f353d28
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 11 deletions.
2 changes: 1 addition & 1 deletion xiblint/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.9.9'
__version__ = '0.9.10'
47 changes: 37 additions & 10 deletions xiblint/rules/color_assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,20 @@

class ColorAssets(Rule):
def __init__(self, config):
asset_catalog_path = config.get('asset_catalog', None)
asset_catalog_path = config.get("asset_catalog", None)
if asset_catalog_path is None:
raise SystemExit("error: Asset catalog not found. Please configure 'asset_catalog'.")
raise SystemExit(
"error: Asset catalog not found. Please configure 'asset_catalog'.",
)

self.assets = glob.glob("{}/**/*.colorset".format(asset_catalog_path))

if not self.assets:
raise SystemExit("error: Failed to load asset catalog at: '{}'".format(asset_catalog_path))
raise SystemExit(
"error: Failed to load asset catalog at: '{}'".format(
asset_catalog_path,
),
)

self.colors = {}

Expand All @@ -25,6 +31,7 @@ def __init__(self, config):
"asset_catalog": "Resources/Color.xcassets"
}
"""

def check(self, context): # type: (XibContext) -> None
for element in context.tree.findall(".//namedColor"):
name = element.get("name")
Expand All @@ -34,26 +41,38 @@ def check(self, context): # type: (XibContext) -> None

expected_color = self._load_color(name)
if not expected_color:
context.error(element, "Named color '{}' is missing from asset catalog.".format(name))
context.error(
element,
"Named color '{}' is missing from asset catalog.".format(name),
)
continue

color_element = element.find("color")
if color_element is None:
context.error(element, "Named color '{}' is missing color definition.".format(name))
context.error(
element,
"Named color '{}' is missing color definition.".format(name),
)
continue

red = color_element.get("red")
green = color_element.get("green")
blue = color_element.get("blue")
alpha = color_element.get("alpha")
if not all([red, green, blue, alpha]):
context.error(element, "Named color '{}' has invalid color value.".format(name))
context.error(
element, "Named color '{}' has invalid color value.".format(name),
)
continue

color = (float(red), float(green), float(blue), float(alpha))

if color != expected_color:
context.error(element, "Color value for '{}' does not match asset catalog.".format(name))
if not self._compare_colors(color, expected_color):
print(color, expected_color)
context.error(
element,
"Color value for '{}' does not match asset catalog.".format(name),
)

def _load_color(self, name):
if name in self.colors:
Expand All @@ -70,8 +89,12 @@ def _load_color(self, name):
return color

def _load_components(self, components):
return (self._load_component(components, "red"), self._load_component(components, "green"),
self._load_component(components, "blue"), self._load_component(components, "alpha"))
return (
self._load_component(components, "red"),
self._load_component(components, "green"),
self._load_component(components, "blue"),
self._load_component(components, "alpha"),
)

def _load_component(self, components, key):
string = components[key]
Expand All @@ -80,3 +103,7 @@ def _load_component(self, components, key):
return float(string)

return float(string) / 255.0

def _compare_colors(self, lhs, rhs):
# Compare with only 4 decimal places
return all(format(l, ".4f") == format(r, ".4f") for l, r in zip(lhs, rhs))

0 comments on commit f353d28

Please sign in to comment.