def test_build_selector(self): css_classes = ( 'padding-10-i-hover', 'color-hfff-before', 'width-1rem-s-selection', 'color-red-checked', 'hfff-hover-i', 'hfff-i-hover', 'color-hfff-hover-i', 'color-hfff-i-hover', ) expected_selector_text = ( '.padding-10-i-hover:hover', '.color-hfff-before::before', '.width-1rem-s-selection::selection', '.color-red-checked:checked', '.hfff-hover-i:hover', '.hfff-i-hover:hover', '.color-hfff-hover-i:hover', '.color-hfff-i-hover:hover', ) property_parser = ClassPropertyParser(class_set=set()) style_builder = CSSBuilder(property_parser=property_parser) for i, css_class in enumerate(css_classes): selector = style_builder.build_selector(css_class=css_class) self.assertEqual(selector.selectorText, expected_selector_text[i])
def test_get_css_text_output_convert_to_em(self): class_set = { 'margin-top-10', 'bgc-h000', 'hide', 'margin-20', 'padding-top-10', 'height-200', 'padding-10', 'valign-middle', 'b', 'width-150', 'width-50', 'font-size-48', 'c-blue', 'margin-top-50px', 'text-align-center', 'height-50px', 'height-150px', 'bold', 'color-hfff' } expected_properties = [ 'background-color: #000', 'vertical-align: middle', 'color: blue', 'margin-top: 3.125em', 'text-align: center', 'height: 3.125em', 'height: 9.375em', 'font-weight: bold', 'color: #fff' ] property_parser = ClassPropertyParser(class_set=class_set) css_builder = CSSBuilder(property_parser=property_parser) css_text = css_builder.get_css_text().decode('utf-8') for expected in expected_properties: self.assertTrue(expected in css_text, msg=expected + ' and ' + css_text) if expected in css_text: css_text = css_text.replace(expected, '')
def test_get_css_text_output_no_conversion(self): class_set = { # 'margin-top-10', 'bgc-h000', 'hide', 'margin-20', 'padding-top-10', 'height-200', 'padding-10', # 'valign-middle', 'b', 'width-150', 'width-50', 'font-size-48', 'c-blue', 'margin-top-50px', # 'text-align-center', 'height-50px', 'height-150px', 'bold', 'color-hfff', 'hf1f', 'hf2f-hover-i', 'hf3f-i-hover', 'color-hf4f-hover-i', 'color-hf5f-i-hover', } expected_properties = [ # 'background-color: #000', 'vertical-align: middle', 'color: blue', 'margin-top: 50px', # 'text-align: center', 'height: 50px', 'height: 150px', 'font-weight: bold', 'color: #fff', 'color: #f1f', 'color: #f2f !important', 'color: #f3f !important', 'color: #f4f !important', 'color: #f5f !important', ] settings.use_em = False property_parser = ClassPropertyParser(class_set=class_set) css_builder = CSSBuilder(property_parser=property_parser) css_text = css_builder.get_css_text().decode('utf-8') for expected in expected_properties: self.assertTrue(expected in css_text, msg=expected + ' and ' + css_text) if expected in css_text: css_text = css_text.replace(expected, '') settings.use_em = True
def parse(recent=True, class_set=set(), css_text=b''): """ It parses every eligible file in the project i.e. file type matches an element of settings.file_types. This ensures that from time to time unused CSS class selectors are removed from blowdry.css. **Order of Operations:** - Initialize settings. - Start performance timer. - Define File all file types/extensions to search for in project_directory - Get all files associated with defined file_types in project_directory - Get set of all defined classes - Filter class names only keeping classes that match the defined class encoding. - Build a set() of valid css properties. Some classes may be removed during cssutils validation. - Output the DRY CSS file. (user command option) - Output the Minified DRY CSS file. (user command option) **Depending on the settings this script generates the following:** - DRY CSS files - blowdry.css |sp| |sp| |sp| |sp| |sp| **human readable** - blowdry.min.css |sp| **minified** - Clashing Alias files (Encoded class selector aliases that are invalid and cannot be used because they clash.) - Markdown |sp| |sp| |sp| |sp| |sp| |sp| **Github** - HTML |sp| |sp| |sp| |sp| |sp| |sp| |sp| |sp| |sp| **Browser** - reStructuredText |sp| **Sphinx** - Property Alias File (Encoded class selector aliases that are valid and can be used to construct class selectors.) - Markdown |sp| |sp| |sp| |sp| |sp| |sp| **Github** - HTML |sp| |sp| |sp| |sp| |sp| |sp| |sp| |sp| |sp| **Browser** - reStructuredText |sp| **Sphinx** - Temporal Statistics **Note:** The default locations of these files can be overridden to suit your needs. **Directory assignments** ``project_directory`` -- Allows ``blowdrycss`` to know where the HTML project is located. It will only search the files in the directory specified here. .. |sp| raw:: html :param css_text: :type recent: bool :param recent: Flag that indicates whether to parse the most recently modified files (True Case) or all eligible files (False Case). :type class_set: set :param class_set: The set of known css class selectors. :type css_text: bytes :param css_text: The current version of the CSS text. """ if settings.timing_enabled: from blowdrycss.timing import Timer timer = Timer() print('\n~~~ blowdrycss started ~~~') # Get files to parse. file_finder = FileFinder(recent=recent) # Create set of all defined classes class_parser = ClassParser(file_dict=file_finder.file_dict) # Unite class sets during on_modified case. if recent: modified_class_set = class_parser.class_set use_this_set = modified_class_set.difference(class_set) else: use_this_set = class_parser.class_set # Filter class names. Only keep classes matching the defined class encoding. class_property_parser = ClassPropertyParser(class_set=use_this_set) logging.info(msg='blowdry.class_property_parser.class_set:\t' + str(class_property_parser.class_set)) use_this_set = class_property_parser.class_set.copy() # Build a set() of valid css properties. Some classes may be removed during cssutils validation. css_builder = CSSBuilder(property_parser=class_property_parser) css_text += bytes(css_builder.get_css_text()) builder_class_set = css_builder.property_parser.class_set.copy() # Build Media Queries if settings.media_queries_enabled: unassigned_class_set = use_this_set.difference(css_builder.property_parser.class_set) css_builder.property_parser.class_set = unassigned_class_set.copy() # Only use unassigned classes css_builder.property_parser.removed_class_set = set() # Clear set media_query_builder = MediaQueryBuilder(property_parser=class_property_parser) logging.debug( msg=( 'blowdry.media_query_builder.property_parser.class_set:\t' + str(media_query_builder.property_parser.class_set) ) ) css_text += bytes(media_query_builder.get_css_text(), 'utf-8') media_class_set = unassigned_class_set.intersection(media_query_builder.property_parser.class_set) if recent: class_set = class_set.union(builder_class_set) class_set = class_set.union(media_class_set) else: class_set = builder_class_set.copy() class_set = class_set.union(media_class_set) else: if recent: class_set = class_set.union(builder_class_set) else: class_set = builder_class_set.copy() logging.debug('\nCSS Text:\n\n' + str(css_text)) print('\nAuto-Generated CSS:') # Output the DRY CSS file. (user setting option) if settings.human_readable: css_file = CSSFile(file_directory=settings.css_directory, file_name='blowdry') css_file.write(css_text=css_text) print(path.join(settings.css_directory, css_file.file_name) + '.css') # Output the Minified DRY CSS file. (user setting option) if settings.minify: css_file = CSSFile(file_directory=settings.css_directory, file_name='blowdry') css_file.minify(css_text=css_text) print(path.join(settings.css_directory, css_file.file_name) + '.min.css') if settings.timing_enabled: timer.report() if settings.minify: print_css_stats(file_name='blowdry') return class_set, css_text