Text-Sass-v1.0.4000755000765000024 012752350155 12624 5ustar00rmpstaff000000000000Text-Sass-v1.0.4/Build.PL000444000765000024 323712752350155 14262 0ustar00rmpstaff000000000000######### # Author: rmp # Last Modified: $Date: 2011-11-05 22:04:35 +0000 (Sat, 05 Nov 2011) $ # Id: $Id: Build.PL 62 2011-11-05 22:04:35Z zerojinx $ # Source: $Source$ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/Build.PL $ # use strict; use warnings; use Module::Build; use lib qw(lib); my $builder = Module::Build->new( module_name => 'Text-Sass', dist_author => 'Roger Pettett ', dist_version_from => 'lib/Text/Sass.pm', dist_abstract => q[Text-Sass - Perl implementation of http://sass-lang.com/], license => 'perl', requires => { 'Carp' => '1.04', 'English' => '1.02', 'Readonly' => '1.03', 'strict' => '1.03', 'warnings' => '1.05', 'Convert::Color' => '0.05', 'POSIX' => '1.09', }, recommends => { 'Data::Dumper' => '2.125', }, build_requires => { 'Test::More' => '0.8', 'Try::Tiny' => '0.06', }, build_recommends => { 'Test::Distribution' => '2.00', 'Test::Perl::Critic' => '1.01', }, 'meta_merge' => { 'keywords' => [ 'Sass', 'SCSS', 'CSS', ], 'resources' => { 'repository' => 'https://github.com/rmp/libtext-sass-perl' } }, script_files => qw(bin/sass2css.pl), # sign => 1, ); $builder->create_build_script(); Text-Sass-v1.0.4/Changes000444000765000024 252712752350155 14262 0ustar00rmpstaff000000000000Changelog for Text-Sass 1.0.4 - support single-line comments from Konstantin Tokarev 1.0.1 - support custom functions. use Text::Sass Functions => [qw(package package)]; 1.0.0 - PR#2 (annulen:multiline_var) from Konstantin Tokarev 0.97 - #80831 comma-separated selectors from BGRIMM #80927 scss to css for nested includes from BGRIMM 0.96 - #77718 pod encoding bug from ANDK - improved URL handling, tests from Dan Markham 0.95 - bugfix for RT#74181 from Andrei Arsenin 0.94 - bugfix for RT#74160 from Andrei Arsenin 0.93 - kicked version number 0.9.3 - downgraded POSIX requirement - RT#72204 0.9.2 - background: url(xxx) no-repeat fix from mk@bluepipe.dk RT#66349 0.9.1 - test fixes - fpu platform differences & RT#63256 0.9 - Function & SCSS support from Bjørn-Olav 0.8 - Flexible indentation fixes, from Bjørn-Olav Retain declaration order, from Bjørn-Olav 0.7 - Better whitespace handling. Very hacky though. A handful of new tests. 0.6 - Better nesting, lots of haphazard debugging; Thanks to tests & queries from Bjørn-Olav Strand 0.4 - Mixins, very rough. Already regretting not using a proper parser/grammar/tokeniser etc. 0.3 - Variables, operators, colour handling 0.2 - Simple nesting; a few more tests 0.1 - Started implementing examples from sass-lang homepage. Basic static conversion seems to work ok. Text-Sass-v1.0.4/LICENSE000444000765000024 1373212752350155 14014 0ustar00rmpstaff000000000000 The "Artistic License" Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder as specified below. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as uunet.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) give non-standard executables non-standard names, and clearly document the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. You may embed this Package's interpreter within an executable of yours (by linking); this shall be construed as a mere form of aggregation, provided that the complete Standard Version of the interpreter is so embedded. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whoever generated them, and may be sold commercially, and may be aggregated with this Package. If such scripts or library files are aggregated with this Package via the so-called "undump" or "unexec" methods of producing a binary executable image, then distribution of such an image shall neither be construed as a distribution of this Package nor shall it fall under the restrictions of Paragraphs 3 and 4, provided that you do not represent such an executable image as a Standard Version of this Package. 7. C subroutines (or comparably compiled subroutines in other languages) supplied by you and linked into this Package in order to emulate subroutines and variables of the language defined by this Package shall not be considered part of this Package, but are the equivalent of input as in Paragraph 6, provided these subroutines do not change the language in any way that would cause it to fail the regression tests for the language. 8. Aggregation of this Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package. 9. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End Text-Sass-v1.0.4/Makefile000444000765000024 317712752350155 14431 0ustar00rmpstaff000000000000MAJOR ?= 1 MINOR ?= 0 SUB ?= 4 PATCH ?= 1 CODENAME ?= $(shell lsb_release -cs) MD5SUM = md5sum SEDI = sed -i ifeq ($(shell uname), Darwin) MD5SUM = md5 -r SEDI = sed -i "" endif all: setup ./Build versions: find lib bin -type f -exec perl -i -pe 's/VERSION\s+=\s+q[[\d.]+]/VERSION = q[$(MAJOR).$(MINOR).$(SUB)]/g' {} \; setup: versions perl Build.PL manifest: setup ./Build manifest clean: setup ./Build clean touch tmp rm -rf build.tap *META*yml *META*json _build Build blib cover_db *gz *deb *rpm tmp MANIFEST.bak test: all TEST_AUTHOR=1 ./Build test verbose=1 cover: clean setup HARNESS_PERL_SWITCHES=-MDevel::Cover prove -Ilib t -MDevel::Cover cover -ignore_re t/ install: setup ./Build install dist: setup ./Build dist deb: manifest make test touch tmp rm -rf tmp mkdir -p tmp/usr/lib/perl5 cp -pR deb-src/* tmp/ cp tmp/DEBIAN/control.tt2 tmp/DEBIAN/control $(SEDI) "s/MAJOR/$(MAJOR)/g" tmp/DEBIAN/control $(SEDI) "s/MINOR/$(MINOR)/g" tmp/DEBIAN/control $(SEDI) "s/PATCH/$(PATCH)/g" tmp/DEBIAN/control $(SEDI) "s/RELEASE/$(RELEASE)/g" tmp/DEBIAN/control $(SEDI) "s/CODENAME/$(CODENAME)/g" tmp/DEBIAN/control rsync --exclude .svn --exclude .git -va lib/* tmp/usr/lib/perl5/ rsync --exclude .svn --exclude .git -va bin/* tmp/usr/bin/ find tmp -type f ! -regex '.*\(\bDEBIAN\b\|\.\bsvn\b\|\bdeb-src\b\|\.\bgit\b\|\.\bsass-cache\b\|\.\bnetbeans\b\).*' -exec $(MD5SUM) {} \; | sed 's/tmp\///' > tmp/DEBIAN/md5sums (cd tmp; fakeroot dpkg -b . ../libtext-sass-perl-$(MAJOR).$(MINOR).$(SUB)-$(PATCH).deb) cpan: clean make dist cpan-upload Text-Sass-v$(MAJOR).$(MINOR).$(PATCH).tar.gz Text-Sass-v1.0.4/MANIFEST000444000765000024 177612752350155 14125 0ustar00rmpstaff000000000000bin/sass2css.pl Build.PL Changes deb-src/DEBIAN/changelog deb-src/DEBIAN/control.tt2 examples/README lib/Text/Sass.pm lib/Text/Sass/Expr.pm lib/Text/Sass/Functions.pm lib/Text/Sass/Token.pm LICENSE Makefile MANIFEST This list of files MANIFEST.SKIP README t/00-critic.t t/00-distribution.t t/00-pod.t t/00-podcoverage.t t/05-expr.t t/10-beauty.t t/10-comments.t t/20-nesting.t t/21-nesting.t t/22-deep.t t/30-variables.t t/40-mixins.t t/50-space.t t/60-functions-extended.t t/60-functions.t t/61-keyword-arguments.t t/62-nested-calls.t t/81-sass-ex.t t/82-sass-ex.t t/90-regression-aa-74181.t t/90-regression-aa.t t/90-regression-background.t t/90-regression-bos.t t/90-regression-wikipedia-nowhitespace.t t/90-regression-wikipedia-parentref.t t/90-regression-wikipedia.t t/91-keep-order.t t/92-no-whitespace.t t/93-parentref-comma.t t/94-scss-linebreaks.t t/lib/special.pm t/RT-62474-accept-spaces.t t/RT-80831-commasep-selectors.t t/RT-80927-nested-includes.t t/RT-80978-nested-ampersand-includes.t META.yml META.json Text-Sass-v1.0.4/MANIFEST.SKIP000444000765000024 21112752350155 14631 0ustar00rmpstaff000000000000^MYMETA.json$ ^MYMETA.yml$ ^META.json$ ^META.yml$ .git .svn _build blib ^Build$ MANIFEST.bak .deb$ .tar.gz$ .rpm$ Text-Sass cover_db tmp Text-Sass-v1.0.4/META.json000444000765000024 346512752350155 14412 0ustar00rmpstaff000000000000{ "abstract" : "Text-Sass - Perl implementation of http://sass-lang.com/", "author" : [ "Roger Pettett " ], "dynamic_config" : 1, "generated_by" : "Module::Build version 0.4218", "keywords" : [ "Sass", "SCSS", "CSS" ], "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Text-Sass", "prereqs" : { "build" : { "requires" : { "Test::More" : "0.8", "Try::Tiny" : "0.06" } }, "configure" : { "requires" : { "Module::Build" : "0.42" } }, "runtime" : { "recommends" : { "Data::Dumper" : "2.125" }, "requires" : { "Carp" : "1.04", "Convert::Color" : "0.05", "English" : "1.02", "POSIX" : "1.09", "Readonly" : "1.03", "strict" : "1.03", "warnings" : "1.05" } } }, "provides" : { "Text::Sass" : { "file" : "lib/Text/Sass.pm", "version" : "v1.0.4" }, "Text::Sass::Expr" : { "file" : "lib/Text/Sass/Expr.pm", "version" : "v1.0.4" }, "Text::Sass::Functions" : { "file" : "lib/Text/Sass/Functions.pm", "version" : "v1.0.4" }, "Text::Sass::Token" : { "file" : "lib/Text/Sass/Token.pm", "version" : "v1.0.4" } }, "release_status" : "stable", "resources" : { "license" : [ "http://dev.perl.org/licenses/" ], "repository" : { "url" : "https://github.com/rmp/libtext-sass-perl" } }, "version" : "v1.0.4", "x_serialization_backend" : "JSON::PP version 2.27300" } Text-Sass-v1.0.4/META.yml000444000765000024 215512752350155 14235 0ustar00rmpstaff000000000000--- abstract: 'Text-Sass - Perl implementation of http://sass-lang.com/' author: - 'Roger Pettett ' build_requires: Test::More: '0.8' Try::Tiny: '0.06' configure_requires: Module::Build: '0.42' dynamic_config: 1 generated_by: 'Module::Build version 0.4218, CPAN::Meta::Converter version 2.150005' keywords: - Sass - SCSS - CSS license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Text-Sass provides: Text::Sass: file: lib/Text/Sass.pm version: v1.0.4 Text::Sass::Expr: file: lib/Text/Sass/Expr.pm version: v1.0.4 Text::Sass::Functions: file: lib/Text/Sass/Functions.pm version: v1.0.4 Text::Sass::Token: file: lib/Text/Sass/Token.pm version: v1.0.4 recommends: Data::Dumper: '2.125' requires: Carp: '1.04' Convert::Color: '0.05' English: '1.02' POSIX: '1.09' Readonly: '1.03' strict: '1.03' warnings: '1.05' resources: license: http://dev.perl.org/licenses/ repository: https://github.com/rmp/libtext-sass-perl version: v1.0.4 x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Text-Sass-v1.0.4/README000444000765000024 221212752350155 13636 0ustar00rmpstaff000000000000Text-Sass - A Naieve Perl implementation of Sass & SCSS http://sass-lang.com/ ============================================================================= https://github.com/rmp/libtext-sass-perl This is most definitely a work-in-progress. It only implements a subset of the specification but it's being actively developed so if there's functionality missing, drop me a line at rmp@psyphi.net and send me patches and tests. And yes, this should all really be done with a proper language tools, i.e. grammar, parser, tokeniser etc. Bugs & Limitations - Compound class/id/element are unreliable: .element1, .element2 ... - Variables are currently global. This can be quite unpleasant. - There is no support for colorfunctions. - There is no support for @extends. - No support of default for values. - No support for #{} interpolation. - No support for @import of sass and scss. - No support for @debug. - No support for @warn. - No support for @if. - No support for @for. - No support for @while. Other than that, you're good to go. Thanks to Bjørn-Olav Strand, Andreas König, Dan Markham, Konstantin Tokarev and others for patches. Text-Sass-v1.0.4/bin000755000765000024 012752350155 13374 5ustar00rmpstaff000000000000Text-Sass-v1.0.4/bin/sass2css.pl000555000765000024 110012752350155 15625 0ustar00rmpstaff000000000000#!/usr/bin/env perl ######### # Author: rmp # Last Modified: $Date: 2010-10-28 17:09:19 +0100 (Thu, 28 Oct 2010) $ # Id: $Id: sass2css.pl 19 2010-10-28 16:09:19Z zerojinx $ # Source: $Source$ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/bin/sass2css.pl $ # use strict; use warnings; use lib qw(lib); use Text::Sass; use Carp; use English qw(-no_match_vars); our $VERSION = '1.00'; my $sass = Text::Sass->new(); if(!scalar @ARGV) { local $RS = undef; my $str = <>; print $sass->sass2css($str) or croak $ERRNO; } Text-Sass-v1.0.4/deb-src000755000765000024 012752350155 14143 5ustar00rmpstaff000000000000Text-Sass-v1.0.4/deb-src/DEBIAN000755000765000024 012752350155 15065 5ustar00rmpstaff000000000000Text-Sass-v1.0.4/deb-src/DEBIAN/changelog000444000765000024 21212752350155 17047 0ustar00rmpstaff000000000000libtext-sass-perl (0.97) unstable; urgency=low * TSP-1 placeholder -- Roger Pettett Fri, 7 Mar 2014 10:56:00 +0000 Text-Sass-v1.0.4/deb-src/DEBIAN/control.tt2000555000765000024 60112752350155 17315 0ustar00rmpstaff000000000000Package: libtext-sass-perl Version: MAJOR.MINOR.SUB-PATCH Section: base Priority: optional Architecture: all Source: libtext-sass-perl Depends: libreadonly-perl,libconvert-color-perl Recommends: libtest-perl-critic-perl, libtest-pod-coverage-perl, libtest-pod-perl,libtry-tiny-perl Maintainer: Roger Pettett Description: Naive implementation of Sass/SCSS preprocessor Text-Sass-v1.0.4/examples000755000765000024 012752350155 14442 5ustar00rmpstaff000000000000Text-Sass-v1.0.4/examples/README000444000765000024 10212752350155 15430 0ustar00rmpstaff000000000000For examples, you're probably best off looking at the tests in t/ Text-Sass-v1.0.4/lib000755000765000024 012752350155 13372 5ustar00rmpstaff000000000000Text-Sass-v1.0.4/lib/Text000755000765000024 012752350155 14316 5ustar00rmpstaff000000000000Text-Sass-v1.0.4/lib/Text/Sass.pm000444000765000024 4730112752350155 15747 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-11-10 16:33:37 +0000 (Sat, 10 Nov 2012) $ # Id: $Id: Sass.pm 75 2012-11-10 16:33:37Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/lib/Text/Sass.pm $ # # Note to reader: # Recursive regex processing can be very bad for your health. # Sass & SCSS are both pretty cool. This module is not. # package Text::Sass; use strict; use warnings; use Carp; use English qw(-no_match_vars); use Text::Sass::Expr; use Text::Sass::Functions; use Text::Sass::Token; use Data::Dumper; use Readonly; our $VERSION = q[1.0.4]; our $DEBUG = 0; our $FUNCTIONS = [qw(Text::Sass::Functions)]; Readonly::Scalar our $DEBUG_SEPARATOR => 30; sub import { my ($class, @args) = @_; if(!scalar @args % 2) { my $args = {@args}; if($args->{Functions}) { for my $functions (@{$args->{Functions}}) { eval "require $functions" or carp qq[Could not require $functions: $EVAL_ERROR]; ## no critic (ProhibitStringyEval) push @{$FUNCTIONS}, $functions; } } } return 1; } sub new { my ($class, $ref) = @_; if(!$ref) { $ref = {}; } bless $ref, $class; return $ref; } sub css2sass { my ($self, $str) = @_; if(!ref $self) { $self = $self->new; } my $symbols = {}; my $stash = []; $self->_parse_css($str, $stash, $symbols); return $self->_stash2sass($stash, $symbols); } sub sass2css { my ($self, $str) = @_; if(!ref $self) { $self = $self->new; } my $symbols = {}; my $stash = []; my $chain = []; $self->{_sass_indent} = 0; $self->_parse_sass($str, $stash, $symbols, $chain); return $self->_stash2css($stash, $symbols); } sub scss2css { my ($self, $str) = @_; if(!ref $self) { $self = $self->new; } my $symbols = {}; my $stash = []; $self->_parse_css($str, $stash, $symbols); return $self->_stash2css($stash, $symbols); } sub _parse_sass { my ($self, $str, $substash, $symbols, $chain) = @_; $DEBUG and print {*STDERR} q[=]x$DEBUG_SEPARATOR, q[begin _parse_sass], q[=]x$DEBUG_SEPARATOR, "\n"; ######### # insert blank links after code2: # code1 # code2 # code3 # code4 # $str =~ s/\n(\S)/\n\n$1/smxg; ######### # strip blank lines from: # # code # $str =~ s/^\s*\n(\s+)/$1/smxg; my $groups = [split /\n\s*?\n/smx, $str]; for my $g (@{$groups}) { $self->_parse_sass_group($substash, $symbols, $chain, $g); } $DEBUG and print {*STDERR} q[=]x$DEBUG_SEPARATOR, q[ end _parse_sass ], q[=]x$DEBUG_SEPARATOR, "\n"; return 1; } sub _parse_sass_group { my ($self, $substash, $symbols, $chain, $group) = @_; my @lines = split /\n/smx, $group; while(my $line = shift @lines) { ######### # /* comment */ # /* comment # $line =~ s{/[*].*?[*]/\s*}{}smx; $line =~ s{/[*].*$}{}smx; ######### # !x = y variable declarations # $line =~ s{^\!(\S+)\s*=\s*(.*?)$}{ $symbols->{variables}->{$1} = $2; $DEBUG and carp qq[VARIABLE $1 = $2]; q[]; }smxegi; ######### # $x : y variable declarations # $line =~ s{^\$(\S+)\s*:\s*(.*?)$}{ $symbols->{variables}->{$1} = $2; $DEBUG and carp qq[VARIABLE $1 = $2]; q[]; }smxegi; ######### # =x | =x(!var) # bla | bla # # mixin declaration # $line =~ s{^=(.*?)$}{ my $mixin_stash = {}; my $remaining = join "\n", @lines; @lines = (); my $proto = $1; my ($func) = $1 =~ /^([^(]+)/smx; ######### # mixins are interpolated later, so we just store the string here # $symbols->{mixins}->{$func} = "$proto\n$remaining\n"; $DEBUG and carp qq[MIXIN $func]; q[]; }smxegi; ######### # @include # # mixin usage # $line =~ s{^\@include\s*(.*?)(?:[(](.*?)[)])?$}{ my ($func, $argstr) = ($1, $2); my $mixin_str = $symbols->{mixins}->{$func}; my $subsymbols = $symbols; # todo: correct scoping - is better as {%{$symbols}} my $values = $argstr ? [split /\s*,\s*/smx, $argstr] : []; my ($varstr) = $mixin_str =~ /^.*?[(](.*?)[)]/smx; my $vars = $varstr ? [split /\s*,\s*/smx, $varstr] : []; for my $var (@{$vars}) { $var =~ s/^[\!\$]//smx; $subsymbols->{variables}->{$var} = shift @{$values}; } $mixin_str =~ s/^.*?\n//smx; my $result = []; $self->_parse_sass($mixin_str, $result, $subsymbols, [@{$chain}]); push @{$substash}, {"+$func" => $result}; $DEBUG and carp qq[DYNAMIC MIXIN $func]; q[]; }smxegi; ######### # @mixin name # bla # # mixin declaration # $line =~ s{^\@mixin\s+(.*?)$}{ my $mixin_stash = {}; my $remaining = join "\n", @lines; @lines = (); my $proto = $1; my ($func) = $1 =~ /^([^(]+)/smx; ######### # mixins are interpolated later, so we just store the string here # $symbols->{mixins}->{$func} = "$proto\n$remaining\n"; $DEBUG and carp qq[MIXIN $func]; q[]; }smxegi; ######### # static +mixin # $line =~ s{^[+]([^(]+)$}{ my $func = $1; my $mixin_str = $symbols->{mixins}->{$func}; $mixin_str =~ s/^.*?\n//smx; my $result = []; $self->_parse_sass($mixin_str, $result, $symbols, [@{$chain}]); my $mixin_tag = (keys %{$result->[0]})[0]; push @{$substash}, {$mixin_tag => (values %{$result->[0]})[0]}; $DEBUG and carp qq[STATIC MIXIN $func / $mixin_tag]; q[]; }smxegi; ######### # interpolated +mixin(value) # $line =~ s{^[+](.*?)[(](.*?)[)]$}{ my ($func, $argstr) = ($1, $2); my $mixin_str = $symbols->{mixins}->{$func}; my $subsymbols = $symbols; # todo: correct scoping - is better as {%{$symbols}} my $values = [split /\s*,\s*/smx, $argstr]; my ($varstr) = $mixin_str =~ /^.*?[(](.*?)[)]/smx; my $vars = [split /\s*,\s*/smx, $varstr]; for my $var (@{$vars}) { $var =~ s/^[\!\$]//smx; $subsymbols->{variables}->{$var} = shift @{$values}; } $mixin_str =~ s/^.*?\n//smx; my $result = []; $self->_parse_sass($mixin_str, $result, $subsymbols, [@{$chain}]); push @{$substash}, {"+$func" => $result}; $DEBUG and carp qq[DYNAMIC MIXIN $func]; q[]; }smxegi; ######### # parent ref # # tag # attribute: value # &:pseudoclass # attribute: value2 # $line =~ s{^(&\s*.*?)$}{$self->_parse_sass_parentref($substash, $symbols, $chain, \@lines, $1)}smxegi; ######### # static and dynamic attr: value # color: #aaa # $line =~ s{^(\S+)\s*[:=]\s*(.*?)$}{ my $key = $1; my $val = $2; $DEBUG and carp qq[ATTR $key = $val]; if($val =~ /^\s*$/smx) { my $remaining = join "\n", @lines; @lines = (); my $ssubstash = []; $self->_parse_sass($remaining, $ssubstash, $symbols, [@{$chain}]); push @{$substash}, { "$key:" => $ssubstash }; } else { push @{$substash}, { $key => $val }; } q[]; }smxegi; ######### # # if ($line =~ /^([ ]+)(\S.*)$/smx) { my $indent = $1; # Indented if (!$self->{_sass_indent}) { $self->{_sass_indent} = length $1; } if ($line =~ /^[ ]{$self->{_sass_indent}}(\S.*)$/smx) { my $process = []; while (my $l = shift @lines) { if($l =~ /^[ ]{$self->{_sass_indent}}(.*)$/smx) { push @{$process}, $1; } elsif ($l !~ /^\s*$/xms) { ######### # put it back where it came from # unshift @lines, $l; last; } } my $remaining = join "\n", $1, @{$process}; $DEBUG and carp qq[INDENTED $line CALLING DOWN REMAINING=$remaining ].Dumper($substash); $self->_parse_sass($remaining, $substash, $symbols, [@{$chain}]); $line = q[]; } else { croak qq[Illegal indent @{[length $indent]} we're using @{[$self->{_sass_indent}]} ($line)]; } } ######### # .class # #id # element # element2, element2 # # $line =~ s{^(\S+.*?)$}{ my $one = $1; $one =~ s/\s+/ /smxg; my $remaining = join "\n", @lines; @lines = (); my $subsubstash = []; $DEBUG and carp qq[ELEMENT $one descending with REMAINING=$remaining]; $DEBUG and carp Dumper($substash); $self->_parse_sass($remaining, $subsubstash, $symbols, [@{$chain}, $one]); push @{$substash}, { $one => $subsubstash }; $DEBUG and carp qq[ELEMENT $one returned]; $DEBUG and carp Dumper($substash); q[]; }smxegi; $DEBUG and $line and carp qq[REMAINING $line]; } return 1; } sub _parse_sass_parentref { ## no critic (ProhibitManyArgs) # todo: tidy this up! my ($self, $substash, $symbols, $chain, $lines, $pseudo) = @_; my $remaining = join "\n", @{$lines}; @{$lines} = (); my $newkey = join q[ ], @{$chain}; $pseudo =~ s/&/&$newkey/smx; my $subsubstash = []; $self->_parse_sass($remaining, $subsubstash, $symbols, ['TBD']); push @{$substash}, {$pseudo => $subsubstash}; return q[]; } sub _css_nestedgroups { my ($self, $str) = @_; my $groups = []; my $groupstr = q[]; my $indent = 0; for my $i (0..length $str ) { my $char = substr $str, $i, 1; $groupstr .= $char; if ($char eq '{') { $indent++; } if ($char eq '}') { $indent--; if ($indent == 0) { push @{$groups}, $groupstr; $groupstr = q[]; } } } return $groups; } sub _css_kvs { my ($self, $str) = @_; my $groups = []; my $groupstr = q[]; my $indent = 0; for my $i (0..length $str) { my $char = substr $str, $i, 1; if ($char eq q[;] and $indent == 0) { push @{$groups}, $groupstr; $groupstr = q[]; } else { $groupstr .= $char; } if ($char eq '{') { $indent++; } if ($char eq '}') { $indent--; if ($indent == 0) { push @{$groups}, $groupstr; $groupstr = q[]; } } } return $groups; } sub _parse_css { my ($self, $str, $substash, $symbols) = @_; ######### # /* comment */ # // comment # $str =~ s{$Text::Sass::Token::COMMENT}{}smxg; $str =~ s{$Text::Sass::Token::SINGLE_LINE_COMMENT}{}smxg; # Normalize line breaks $str =~ s/\n//sg; ## no critic (RegularExpressions) $str =~ s/;/;\n/sg; ## no critic (RegularExpressions) $str =~ s/{/{\n/sg; ## no critic (RegularExpressions) $str =~ s/}/}\n/sg; ## no critic (RegularExpressions) ######### # scss definitions # $str =~ s{^\s*\$(\S+)\s*:\s*(.*?)\s*\;}{ $symbols->{variables}->{$1} = $2; $DEBUG and carp qq[VARIABLE $1 = $2]; q[]; }smxegi; my $groups = $self->_css_nestedgroups($str); for my $g (@{$groups}) { my ($tokens, $block) = $g =~ m/([^{]*)[{](.*)[}]/smxg; $tokens =~ s/^\s+//smx; $tokens =~ s/\s+$//smx; $tokens =~ s/\n\s+/\n/smx; $tokens =~ s/\s+\n/\n/smx; if ($tokens =~ /^\s*\@mixin\s+(.*)$/smx) { my $proto = $1; my ($func) = $1 =~ /^([^(]+)/smx; $symbols->{mixins}->{$func} = "$proto {\n$block\n}\n"; $DEBUG and carp qq[MIXIN $func]; next; } my $kvs = $self->_css_kvs($block); my $ssubstash = []; for my $kv (@{$kvs}) { $kv =~ s/^\s+//smx; $kv =~ s/\s+$//smx; if(!$kv) { next; } if ($kv =~ /[{].*[}]/smx) { $self->_parse_css( $kv, $ssubstash, $symbols ); next; } if ($kv =~ /^\s*\@include\s+(.*?)(?:[(](.*?)[)])?$/xms) { my ($func, $argstr) = ($1, $2); my $mixin_str = $symbols->{mixins}->{$func}; my $subsymbols = $symbols; # todo: correct scoping - is better as {%{$symbols}} my $values = $argstr ? [split /\s*,\s*/smx, $argstr] : []; my ($varstr) = $mixin_str =~ /^.*?[(](.*?)[)]/smx; my ($proto) = $mixin_str =~ /^\s*([^{]*\S)\s*[{]/smx; my $vars = $varstr ? [split /\s*,\s*/smx, $varstr] : []; for my $var (@{$vars}) { $var =~ s/^[\!\$]//smx; $subsymbols->{variables}->{$var} = shift @{$values}; } my $result = []; $self->_parse_css($mixin_str, $result, $subsymbols); push @{$ssubstash}, @{$result->[0]->{$proto}}; $DEBUG and carp qq[DYNAMIC MIXIN $func]; next; } if ($kv =~ /^\s*\@extend\s+(.*?)$/xms) { my ($selector) = ($1, $2); carp q[@extend not yet implemented]; ## no critic (RequireInterpolationOfMetachars) next; } my ($key, $value) = split /:/smx, $kv, 2; $key =~ s/^\s+//smx; $key =~ s/\s+$//smx; $value =~ s/^\s+//smx; $value =~ s/\s+$//smx; push @{$ssubstash}, { $key => $value }; } ######### # post-process parent references '&' # my $parent_processed = []; #carp qq[SUBSTASH=].Dumper($substash); for my $child (@{$ssubstash}) { #carp qq[CHILD=].Dumper($child); my ($k) = keys %{$child}; my ($v) = $child->{$k}; #carp qq[post-process k=$k v=$v tokens=$tokens]; $k =~ s{(.*)&}{&$1$tokens}smx; #carp qq[post-process kafter=$k]; push @{$parent_processed}, { $k => $v }; #carp Dumper($substash); #carp Dumper({$tokens => $parent_processed}); } push @{$substash}, { $tokens => $parent_processed }; } return 1; } sub _stash2css { my ($self, $stash, $symbols) = @_; my $groups = []; my $delayed = []; #carp qq[STASH2CSS: ].Dumper($stash); for my $stash_line (@{$stash}) { for my $k (keys %{$stash_line}) { my $vk = $k; $vk =~ s/\s+/ /smx; if($k =~ /&/smx) { ($vk) = $k =~ /&(.*)$/smx; $stash_line->{$vk} = $stash_line->{$k}; delete $stash_line->{$k}; $k = $vk; } my $str = "$vk {\n"; if(!ref $stash_line->{$k}) { $str .= sprintf q[ %s: %s], $vk, $stash_line->{$k}; } else { for my $attr_line (@{$stash_line->{$k}}) { for my $attr (sort keys %{$attr_line}) { my $val = $attr_line->{$attr}; if($attr =~ /^[+]/smx) { $attr = q[]; } if($attr =~ /:$/smx) { ######### # font: # family: foo; # size: bar; # my $rattr = $attr; $rattr =~ s/:$//smx; for my $val_line (@{$val}) { for my $k2 (sort keys %{$val_line}) { $str .= sprintf qq[ %s-%s: %s;\n], $rattr, $k2, $self->_expr($stash, $symbols, $val_line->{$k2}); } } next; } if(ref $val) { if($attr) { $attr = sprintf q[ %s], $attr; } my $rattr = $k . ($attr ? $attr : q[]); if($k =~ /,/smx) { $rattr = join q[, ], map { "$_$attr" } split /\s*,\s*/smx, $k; } if($attr =~ /,/smx) { $attr =~ s/^\s//smx; $rattr = join q[, ], map { "$k $_" } split /\s*,\s*/smx, $attr; } # TODO: What if both have ,? push @{$delayed}, $self->_stash2css([{$rattr => $val}], $symbols); next; } $str .= sprintf qq[ %s: %s;\n], $attr, $self->_expr($stash, $symbols, $val); } } } $str .= "}\n"; if($str !~ /[{]\s*[}]/smx) { push @{$groups}, $str; } push @{$groups}, @{$delayed}; $delayed = []; } } return join "\n", @{$groups}; } sub _expr { my ($self, $stash, $symbols, $expr) = @_; my $vars = $symbols->{variables} || {}; ######### # Do variable expansion # $expr =~ s/\!($Text::Sass::Token::IDENT)/{$vars->{$1}||"\!$1"}/smxeg; $expr =~ s/\$($Text::Sass::Token::IDENT)/{$vars->{$1}||"\$$1"}/smxeg; # TODO: should have lwp, so that url() will work { # Functions while ($expr =~ /^(.*?)((\S+)\s*[(]([^)]+)[)](.*)$)/smx) { my $start = $1; my $mstr = $2; my $func = $3; my $varstr = $4; my $end = $5; ######### # We want hyphenated 'adjust-hue' to work # $func =~ s/\-/_/gsmx; my ($implementor) = [grep { $_->can($func); } @{$FUNCTIONS}]->[0]; if (!$implementor) { $start = $self->_expr($stash, $symbols, $start); $end = $self->_expr($stash, $symbols, $end); ######### # not happy with this here. It probably at least belongs in Expr # - and should include any other CSS stop-words # if($end =~ /repeat|left|top|right|bottom/smx) { ## no-repeat, repeat-x, repeat-y $end = q[]; } $expr = $start . $mstr . $end; last; } ######### # TODO: Should support darken(#323, something(4+5, 5)) # my @vars = split /,/smx, $varstr; for my $var (@vars) { $var =~ s/^\s//smx; $var = $self->_expr($stash, $symbols, $var); } my $res = $implementor->$func(@vars); $expr =~ s/\Q$mstr\E/$res/smx; last; } } my @parts = split /\s+/smx, $expr; Readonly::Scalar my $BINARY_OP_PARTS => 3; if(scalar @parts == $BINARY_OP_PARTS) { my $ret = Text::Sass::Expr->expr(@parts); if (defined $ret) { return $ret; } } return $expr; } sub _stash2sass { my ($self, $stash, $symbols) = @_; my $groups = []; # TODO: Write symbols for my $stashline (@{$stash}) { for my $k (keys %{$stashline}) { my $str = "$k\n"; for my $attrline (@{$stashline->{$k}}){ for my $attr (sort keys %{$attrline}) { my $val = $attrline->{$attr}; $str .= sprintf qq[ %s: %s\n], $attr, $val; } } push @{$groups}, $str; } } return join "\n", @{$groups}; } 1; __END__ =encoding utf8 =head1 NAME Text::Sass - A Naieve Perl implementation of Sass & SCSS. =head1 VERSION See Text/Sass.pm =head1 SYNOPSIS use Text::Sass; my $sass = Text::Sass->new(); print $sass->sass2css(<<'EOF'); $font-stack: Helvetica, sans-serif $primary-color: #333 body font: 100% $font-stack color: $primary-color EOF print $sass->scss2css(<<'EOF'); $font-stack: Helvetica, sans-serif; $primary-color: #333; body { font: 100% $font-stack; color: $primary-color; } EOF =head1 DESCRIPTION This is a pure perl implementation of Sass and SCSS languages. Currently it implements only a subset of the specification. L =head1 SUBROUTINES/METHODS =head2 new - Constructor - nothing special my $oSass = Text::Sass->new; =head2 css2sass - Translate CSS to Sass my $sSass = $oSass->css2sass($sCSS); =head2 sass2css - Translate Sass to CSS my $sCSS = $oSass->sass2css($sSass); =head2 scss2css - Translate Scss to CSS my $sCSS = $oSass->scss2css($sScss); =head1 DEPENDENCIES =over =item L =item L =back =head1 INCOMPATIBILITIES All variables are currently global. This can be quite unpleasant. =head1 BUGS AND LIMITATIONS See README =head1 SEE ALSO L - Perl binding for libsass. Consider using it if you need higher level of language conformance and/or faster execution. L - Yet another libsass binding. L - Sass and SCSS support for all Plack frameworks. Can use this module as one of its backends. =head1 AUTHOR Roger Pettett Ermp@psyphi.netE =head1 DIAGNOSTICS Set $Text::Sass::DEBUG = 1; =head1 CONFIGURATION AND ENVIRONMENT Nothing required beyond $DEBUG =head1 LICENSE AND COPYRIGHT This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.10 or, at your option, any later version of Perl 5 you may have available. =cut Text-Sass-v1.0.4/lib/Text/Sass000755000765000024 012752350155 15227 5ustar00rmpstaff000000000000Text-Sass-v1.0.4/lib/Text/Sass/Expr.pm000444000765000024 1104312752350155 16657 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: Expr.pm 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/lib/Text/Sass/Expr.pm $ # package Text::Sass::Expr; use strict; use warnings; use Carp; use Readonly; our $VERSION = q[1.0.4]; Readonly::Scalar our $SHADE_MAX => 255; # yes, this should be tokenised and probably use overloading our $OPS = { q[-] => sub { my ($x, $y) = @_; return $x - $y; }, q[+] => sub { my ($x, $y) = @_; return $x + $y; }, q[/] => sub { my ($x, $y) = @_; return $x / $y; }, q[*] => sub { my ($x, $y) = @_; return $x * $y; }, q[#-] => sub { my ($x, $y) = @_; my ($xr, $xg, $xb) = @{$x}; my ($yr, $yg, $yb) = @{$y}; my $nr = $xr-$yr; my $ng = $xg-$yg; my $nb = $xb-$yb; if($nr < 0) { $nr = 0; } if($ng < 0) { $ng = 0; } if($nb < 0) { $nb = 0; } return rgb_to_hex(undef,[$nr, $ng, $nb]); }, q[#+] => sub { my ($x, $y) = @_; my ($xr, $xg, $xb) = @{$x}; my ($yr, $yg, $yb) = @{$y}; my $nr = $xr+$yr; my $ng = $xg+$yg; my $nb = $xb+$yb; if($nr > $SHADE_MAX) { $nr = $SHADE_MAX; } if($ng > $SHADE_MAX) { $ng = $SHADE_MAX; } if($nb > $SHADE_MAX) { $nb = $SHADE_MAX; } return rgb_to_hex(undef,[$nr, $ng, $nb]); }, }; Readonly::Scalar our $MM2CM => 0.1; Readonly::Scalar our $CM2MM => 10; Readonly::Scalar our $IN2CM => 2.54; Readonly::Scalar our $CM2IN => 1/2.54; Readonly::Scalar our $IN2MM => 25.4; Readonly::Scalar our $MM2IN => 1/25.4; Readonly::Scalar our $PC2PT => 12; Readonly::Scalar our $PT2PC => 1/12; our $CONV = { q[mm:cm] => sub { my ($v) = @_; return $v*$MM2CM; }, q[cm:mm] => sub { my ($v) = @_; return $v*$CM2MM; }, q[in:cm] => sub { my ($v) = @_; return $v*$IN2CM; }, q[cm:in] => sub { my ($v) = @_; return $v*$CM2IN; }, q[in:mm] => sub { my ($v) = @_; return $v*$IN2MM; }, q[mm:in] => sub { my ($v) = @_; return $v*$MM2IN; }, q[pc|pt] => sub { my ($v) = @_; return $v*$PC2PT; }, q[pt|pc] => sub { my ($v) = @_; return $v*$PT2PC; }, }; sub expr { my ($pkg, $part1, $op, $part2) = @_; $part1 =~ s/[#](.)(.)(.)(\b)/#${1}${1}${2}${2}${3}${3}$4/smxgi; $part2 =~ s/[#](.)(.)(.)(\b)/#${1}${1}${2}${2}${3}${3}$4/smxgi; my ($p1, $u1) = @{$pkg->units($part1)}; my ($p2, $u2) = @{$pkg->units($part2)}; return if(!defined $p1); if(!$u1) { $u1 = q[]; } if(!$u2) { $u2 = q[]; } if(!$u1 && $u2) { $u1 = $u2; } if(!$u2 && $u1) { $u2 = $u1; } if($u1 ne $u2 && $u1 ne q[#] && $u2 ne q[#]) { $p2 = $pkg->convert($p2, $u2, $u1); $u2 = $u1; } if(!exists $OPS->{$op}) { if ($op =~ /^\w/smx) { return; } elsif ($op =~ /\S{2,}/smx) { return; } croak qq[Cannot "$op"]; } if($u1 eq q[#]) { my $cb = $OPS->{"#$op"}; return sprintf q[#%s], $cb->($p1||[0,0,0], $p2||[0,0,0]); } return sprintf q[%s%s], $OPS->{$op}->($p1||0, $p2||0), $u1; } sub units { my ($pkg, $token) = @_; if($token =~ /^[#]/smx) { $token =~ s/^[#]//smx; return [$pkg->hex_to_rgb($token), q[#]]; } my ($val, $units) = $token =~ /([\d.]+)(px|pt|pc|em|ex|mm|cm|in|%|)/smx; return [$val, $units]; } sub rgb_to_hex { my ($pkg, $triple_ref) = @_; return sprintf q[%02x%02x%02x], @{$triple_ref}; } sub hex_to_rgb { my ($pkg, $hex) = @_; my ($r, $g, $b) = unpack q[A2A2A2], $hex; return [hex $r, hex $g, hex $b]; } sub convert { my ($pkg, $val, $from, $to) = @_; my $fromto = "$from:$to"; if(!exists $CONV->{$fromto}) { croak qq[Cannot convert from $from to $to]; } return $CONV->{$fromto}->($val); } 1; __END__ =encoding utf8 =head1 NAME Text::Sass::Expr =head1 VERSION $LastChangedRevision: 71 $ =head1 SYNOPSIS =head1 DESCRIPTION =head1 SUBROUTINES/METHODS =head2 expr =head2 units =head2 rgb_to_hex =head2 hex_to_rgb =head2 convert =head1 DIAGNOSTICS =head1 CONFIGURATION AND ENVIRONMENT =head1 DEPENDENCIES =over =item strict =item warnings =item Carp =item Readonly =back =head1 INCOMPATIBILITIES =head1 BUGS AND LIMITATIONS =head1 AUTHOR $Author: Roger Pettett$ =head1 LICENSE AND COPYRIGHT This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.10 or, at your option, any later version of Perl 5 you may have available. =cut Text-Sass-v1.0.4/lib/Text/Sass/Functions.pm000444000765000024 1766012752350155 17724 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: bolav # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: Functions.pm 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/lib/Text/Sass/Functions.pm $ # package Text::Sass::Functions; use strict; use warnings; use Carp; use Convert::Color; use Text::Sass::Expr; use POSIX qw(); use Readonly; our $VERSION = q[1.0.4]; Readonly::Scalar my $PERC => 100; sub _color { my ($self, $color) = @_; $color =~ s/[#](.)(.)(.)(\b)/#${1}${1}${2}${2}${3}${3}$4/smxgi; $color = Text::Sass::Expr->units($color); if ($color->[1] eq q[#]) { return Convert::Color->new(q[rgb8:].$color->[0]->[0].q[,].$color->[0]->[1].q[,].$color->[0]->[2]); } croak 'not a color '.$color; } sub _value { my ($self, $value) = @_; $value = Text::Sass::Expr->units($value); if ($value->[1] eq q[%]) { return $value->[0] / $PERC; } elsif ($value->[1] eq q[]) { return $value->[0]; } croak 'Unknown unit '.$value->[1].' for value'; } ######### # RGB Functions # sub rgb { my ($self, $r, $g, $b) = @_; my $cc = Convert::Color->new( "rgb8:$r,$g,$b" ); return q[#].$cc->as_rgb8->hex; } # TODO: rgba sub red { my ($self, $color) = @_; return $self->_color($color)->as_rgb8->red; } sub green { my ($self, $color) = @_; return $self->_color($color)->as_rgb8->green; } sub blue { my ($self, $color) = @_; return $self->_color($color)->as_rgb8->blue; } sub mix { my ($self, $c1, $c2, $w) = @_; # TODO: Weight not supported $w ||= '50%'; $c1 = $self->_color($c1); $c2 = $self->_color($c2); $w = $self->_value($w); my $w2 = 1-$w; my $r = int(($c1->as_rgb8->red * $w) + ($c2->as_rgb8->red * $w2)) ; my $g = int(($c1->as_rgb8->green * $w) + ($c2->as_rgb8->green * $w2)) ; my $b = int(($c1->as_rgb8->blue * $w) + ($c2->as_rgb8->blue * $w2)) ; return q[#].Convert::Color->new("rgb8:$r,$g,$b")->hex; } ######### # HSL functions # sub hsl { my ($self, $h, $s, $l) = @_; $s = $self->_value($s); $l = $self->_value($l); my $cc = Convert::Color->new( "hsl:$h,$s,$l" ); return q[#].$cc->as_rgb8->hex; } # TODO: hsla sub hue { my ($self, $color) = @_; return $self->_color($color)->as_hsl->hue; } sub saturation { my ($self, $color) = @_; return $self->_color($color)->as_hsl->saturation; } sub lightness { my ($self, $color) = @_; return $self->_color($color)->as_hsl->lightness; } sub adjust_hue { my ($self, $color, $value) = @_; my $cc = $self->_color($color); my $hsl = $cc->as_hsl; my $new_hsl = Convert::Color->new( sprintf q[hsl:%s,%s,%s], $hsl->hue+$value, $hsl->saturation, $hsl->lightness ); return q[#].$new_hsl->as_rgb8->hex; } sub lighten { my ($self, $color, $value) = @_; $value = $self->_value($value); my $cc = $self->_color($color); my $hsl = $cc->as_hsl; my $new_hsl = Convert::Color->new( sprintf q[hsl:%s,%s,%s], $hsl->hue, $hsl->saturation, $hsl->lightness+$value ); return q[#].$new_hsl->as_rgb8->hex; } sub darken { my ($self, $color, $value) = @_; $value = $self->_value($value); my $cc = $self->_color($color); my $hsl = $cc->as_hsl; my $new_hsl = Convert::Color->new( sprintf q[hsl:%s,%s,%s], $hsl->hue, $hsl->saturation, $hsl->lightness-$value ); return q[#].$new_hsl->as_rgb8->hex; } sub saturate { my ($self, $color, $value) = @_; $value = $self->_value($value); my $cc = $self->_color($color); my $hsl = $cc->as_hsl; my $new_hsl = Convert::Color->new( sprintf q[hsl:%s,%s,%s], $hsl->hue, $hsl->saturation+$value, $hsl->lightness ); return q[#].$new_hsl->as_rgb8->hex; } sub desaturate { my ($self, $color, $value) = @_; $value = $self->_value($value); my $cc = $self->_color($color); my $hsl = $cc->as_hsl; my $sat = ($hsl->saturation-$value); if ($sat < 0) { $sat = 0; } my $new_hsl = Convert::Color->new( sprintf q[hsl:%s,%s,%s], $hsl->hue, $sat, $hsl->lightness ); return q[#].$new_hsl->as_rgb8->hex; } sub grayscale { my ($self, $color) = @_; return $self->desaturate($color, "$PERC%"); } sub complement { my ($self, $color) = @_; Readonly::Scalar my $COMP_DEGREES => 180; return $self->adjust_hue($color, $COMP_DEGREES); } ######### # STRING Functions # sub unquote { my ($self, $str) = @_; $str =~ s/^\"(.*)\"/$1/xms; $str =~ s/^\'(.*)\'/$1/xms; return $str; } sub quote { my ($self, $str) = @_; if ($str =~ /^\"(.*)\"/xms) { return $str; } if ($str =~ /^\'(.*)\'/xms) { return $str; } return qq["$str"]; } # NUMBER functions sub percentage { my ($self, $num) = @_; return ($num * $PERC) . q[%]; } sub round { my ($self, $str) = @_; my $num = Text::Sass::Expr->units($str); return sprintf q[%.0f%s], $num->[0], $num->[1]; } sub ceil { my ($self, $str) = @_; my $num = Text::Sass::Expr->units($str); return POSIX::ceil($num->[0]).$num->[1]; } sub floor { my ($self, $str) = @_; my $num = Text::Sass::Expr->units($str); return POSIX::floor($num->[0]).$num->[1]; } sub abs { ## no critic (Homonym) my ($self, $str) = @_; my $num = Text::Sass::Expr->units($str); return POSIX::abs($num->[0]).$num->[1]; } ######### # Introspective functions # sub unit { my ($self, $str) = @_; my $num = Text::Sass::Expr->units($str); return q["].$num->[1].q["]; } sub unitless { my ($self, $str) = @_; my $num = Text::Sass::Expr->units($str); return $num->[1] ? 0 : 1; } 1; __END__ =encoding utf8 =head1 NAME Text::Sass::Functions =head1 VERSION $LastChangedRevision: 71 $ =head1 SYNOPSIS =head1 DESCRIPTION =head1 SUBROUTINES/METHODS =head2 rgb(red, green, blue) Converts triplet into a color. =head2 red(color) Returns the red part of a color. =head2 green(color) Returns the green part of a color. =head2 blue(color) Returns the blue part og a color. =head2 mix(color1, color2, weight = 50%) Mixes two colors together. =head2 hsl(hue, saturation, lightness) Converts as hsl triplet into a color. =head2 hue(color) Returns the hue part of a color. =head2 saturation(color) Returns the saturation part of a color. =head2 lightness(color) Returns the lightness part of a color. =head2 adjust_hue(color) Changes the hue of a color, can be called as adjust-hue. =head2 lighten(color, amount) Makes a color lighter. =head2 darken(color, amount) Makes a color darker. =head2 saturate(color, amount) Makes a color more saturated. =head2 desaturate(color, amount) Makes a color less saturated. =head2 grayscale(color) Converts a color to grayscale. =head2 complement(color) Returns the complement of a color. =head2 unquote(str) Removes the quotes from a string. =head2 quote(str) Adds quotes to a string. =head2 percentage(num) Converts a unitless number to a percentage. =head2 round(num) Rounds a number to the nearest whole number. =head2 ceil(num) Rounds a number up to the nearest whole number. =head2 floor(num) Rounds a number down to the nearest whole number. =head2 abs(num) Returns the absolute value of a number. =head2 unit(num) Returns the unit of a value. =head2 unitless(num) Returns true if the number has no unit. =head1 DIAGNOSTICS =head1 CONFIGURATION AND ENVIRONMENT =head1 DEPENDENCIES =over =item strict =item warnings =item Carp =item POSIX =item Readonly =item Convert::Color =item Text::Sass::Expr =back =head1 INCOMPATIBILITIES =head1 BUGS AND LIMITATIONS Missing alpha routines rgba & hsla methods. mix() doesn't support weight. =head1 AUTHOR Author: Bjørn-Olav Strand =head1 LICENSE AND COPYRIGHT This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.10 or, at your option, any later version of Perl 5 you may have available. =cut Text-Sass-v1.0.4/lib/Text/Sass/Token.pm000444000765000024 255012752350155 17004 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: annulen # Last Modified: $Date$ # Id: $Id$ # $HeadURL$ # package Text::Sass::Token; use strict; use warnings; use Readonly; our $VERSION = q[1.0.4]; # TODO: Use token patterns from original sass and use them consistently Readonly our $ESCAPE => qr/\\./smx; Readonly our $NMCHAR => qr/[^\s:\\]|$ESCAPE/smx; Readonly our $IDENT => qr/(?:$NMCHAR)+/smx; # Next patterns are already consistent with Sass Readonly our $COMMENT => qr{/[*]([^*]|[*]+[^*])*[*]*[*]/}smx; Readonly our $SINGLE_LINE_COMMENT => qr{\s//.*}mx; ## no critic (RequireDotMatchAnything) 1; __END__ =encoding utf8 =head1 NAME Text::Sass::Token =head1 VERSION =head1 SYNOPSIS use Text::Sass::Token; =head1 DESCRIPTION =head1 SUBROUTINES/METHODS =head1 DEPENDENCIES =over =item L =back =head1 INCOMPATIBILITIES =head1 BUGS AND LIMITATIONS See README =head1 SEE ALSO =head1 AUTHOR Roger Pettett Ermp@psyphi.netE =head1 DIAGNOSTICS =head1 CONFIGURATION AND ENVIRONMENT =head1 LICENSE AND COPYRIGHT This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.10 or, at your option, any later version of Perl 5 you may have available. =cut Text-Sass-v1.0.4/t000755000765000024 012752350155 13067 5ustar00rmpstaff000000000000Text-Sass-v1.0.4/t/00-critic.t000444000765000024 203412752350155 15102 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-11-10 16:33:37 +0000 (Sat, 10 Nov 2012) $ # Id: $Id: 00-critic.t 75 2012-11-10 16:33:37Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/00-critic.t $ # package critic; use strict; use warnings; use Test::More; use English qw(-no_match_vars); our $VERSION = 1; if ( not $ENV{TEST_AUTHOR} ) { my $msg = 'Author test. Set $ENV{TEST_AUTHOR} to a true value to run.'; plan( skip_all => $msg ); } eval { require Test::Perl::Critic; }; if($EVAL_ERROR) { plan skip_all => 'Test::Perl::Critic not installed'; } else { Test::Perl::Critic->import( -severity => 1, -exclude => [qw(CodeLayout::RequireTidyCode NamingConventions::Capitalization PodSpelling ValuesAndExpressions::RequireConstantVersion ControlStructures::ProhibitDeepNests)], ); all_critic_ok(); } 1; Text-Sass-v1.0.4/t/00-distribution.t000444000765000024 133112752350155 16343 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 00-distribution.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/00-distribution.t $ # package distribution; use strict; use warnings; use Test::More; use English qw(-no_match_vars); our $VERSION = 1; eval { require Test::Distribution; }; if($EVAL_ERROR) { plan skip_all => 'Test::Distribution not installed'; } else { Test::Distribution->import('not' => 'prereq'); # Having issues with Test::Dist seeing my PREREQ_PM :( } 1; Text-Sass-v1.0.4/t/00-pod.t000444000765000024 104112752350155 14404 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 00-pod.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/00-pod.t $ # use strict; use warnings; use Test::More; eval { require Test::Pod; Test::Pod->import(); }; plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; all_pod_files_ok(); Text-Sass-v1.0.4/t/00-podcoverage.t000444000765000024 103412752350155 16122 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 00-podcoverage.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/00-podcoverage.t $ # use Test::More; eval "use Test::Pod::Coverage 1.00"; plan skip_all => "Test::Pod::Coverage 1.00 required for testing POD coverage" if $@; all_pod_coverage_ok(); Text-Sass-v1.0.4/t/05-expr.t000444000765000024 230712752350155 14613 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 05-expr.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/05-expr.t $ # use strict; use warnings; use Test::More; our @CONVS = ( [1, "cm", 10, "mm"], [1, 'in', 2.54, 'cm'], [1, 'in', 25.4, 'mm'], ); our @EXPRS = ( ["10cm - 1cm", "9cm"], ["10cm - 1mm", "9.9cm"], ["1in / 10cm", "0.254in"], ["#3bbfce - #111111", "#2aaebd"], ); plan tests => 7 + scalar @EXPRS; my $pkg = 'Text::Sass::Expr'; use_ok($pkg); { is_deeply($pkg->units('10px'), [10, 'px'], '10px units'); } { is_deeply($pkg->units('2'), [2, ''], '2 units'); } { is_deeply($pkg->units('#efefff'), [[239,239,255], '#'], '#efefff units'); } for my $set (@CONVS) { is($pkg->convert($set->[0], $set->[1], $set->[3]), $set->[2], "$set->[0]$set->[1] = $set->[2]$set->[3]"); } for my $set (@EXPRS) { my @bits = split /\s/smx, $set->[0]; is($pkg->expr(@bits), $set->[1], "$set->[0] = $set->[1]"); } Text-Sass-v1.0.4/t/10-beauty.t000444000765000024 153712752350155 15126 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 10-beauty.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/10-beauty.t $ # use strict; use warnings; use Text::Sass; use Test::More tests => 2; my $sass_str = <<"EOT"; h1 height: 118px margin-top: 1em .tagline font-size: 26px text-align: right EOT my $css_str = <<"EOT"; h1 { height: 118px; margin-top: 1em; } .tagline { font-size: 26px; text-align: right; } EOT { my $sass = Text::Sass->new(); is($sass->css2sass($css_str), $sass_str, 'css2sass'); } { my $sass = Text::Sass->new(); is($sass->sass2css($sass_str), $css_str, 'sass2css'); } Text-Sass-v1.0.4/t/10-comments.t000444000765000024 107112752350155 15453 0ustar00rmpstaff000000000000use strict; use warnings; use Test::More tests => 1; use Text::Sass; { my $str = <<"EOT"; /* This comment is * several lines long. * since it uses the CSS comment syntax, * it will appear in the CSS output. */ body { color: black; } // These comments are only one line long each. // They won't appear in the CSS output, // since they use the single-line comment syntax. a { color: green; } EOT my $sass = Text::Sass->new; is($sass->scss2css($str), <<"EOT", "strip multi-line and single-line comments"); body { color: black; } a { color: green; } EOT } Text-Sass-v1.0.4/t/20-nesting.t000444000765000024 177712752350155 15313 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 20-nesting.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/20-nesting.t $ # use strict; use warnings; use Text::Sass; use Test::More tests => 2; { my $sass_str = <new(); is($sass->sass2css($sass_str), $css_str, 'sass2css'); } { my $sass_str = <new(); is($sass->sass2css($sass_str), $css_str, 'sass2css'); } Text-Sass-v1.0.4/t/21-nesting.t000444000765000024 250412752350155 15301 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 21-nesting.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/21-nesting.t $ # use strict; use Test::More tests => 2; use Text::Sass; { my $sass_str = <new(); is($sass->sass2css($sass_str), $css_str, 'sass2css multilevel nesting'); } { my $sass_str = <new(); is($sass->sass2css($sass_str), $css_str, 'sass2css multilevel nesting'); } Text-Sass-v1.0.4/t/22-deep.t000444000765000024 161412752350155 14551 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 22-deep.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/22-deep.t $ # use strict; use warnings; use Text::Sass; use Test::More tests => 1; { my $sass_str = <new(); is($sass->sass2css($sass_str), $css_str, 'sass2css'); } Text-Sass-v1.0.4/t/30-variables.t000444000765000024 230012752350155 15574 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 30-variables.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/30-variables.t $ # use strict; use warnings; use Text::Sass; use Test::More tests => 2; { my $sass_str = <<"EOT"; !blue = #3bbfce !margin = 16px .content_navigation border-color = !blue color = !blue - #111 .border padding = !margin / 2 margin = !margin / 2 border-color = !blue EOT my $css_str = <<"EOT"; .content_navigation { border-color: #3bbfce; color: #2aaebd; } .border { padding: 8px; margin: 8px; border-color: #3bbfce; } EOT my $sass = Text::Sass->new(); is($sass->sass2css($sass_str), $css_str, 'sass variables'); } { my $sass_str = <<'EOT'; !blue\: = #3bbfce .content_navigation border-color = !blue\: EOT my $css_str = <<"EOT"; .content_navigation { border-color: #3bbfce; } EOT my $sass = Text::Sass->new(); is($sass->sass2css($sass_str), $css_str, 'sass variable with escaped colon in name'); } Text-Sass-v1.0.4/t/40-mixins.t000444000765000024 311712752350155 15143 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 40-mixins.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/40-mixins.t $ # use strict; use warnings; use Text::Sass; use Test::More tests => 3; # $Text::Sass::DEBUG = 1; { my $sass_str = <new(); is($sass->sass2css($sass_str), $css_str, 'static mixin'); } { my $sass_str = <new(); is($sass->sass2css($sass_str), $css_str, 'dynamic mixin, one variable'); } { my $sass_str = <new(); is($sass->sass2css($sass_str), $css_str, 'complex mixin, static + dynamic'); } } Text-Sass-v1.0.4/t/50-space.t000444000765000024 225512752350155 14732 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 50-space.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/50-space.t $ # use strict; use warnings; use Test::More tests => 2; use Text::Sass; { my $sass = <new; is($ts->sass2css($sass), $css, 'without extra whitespace'); } { my $sass = <new; is($ts->sass2css($sass), $css, 'with extra whitespace'); } Text-Sass-v1.0.4/t/60-functions-extended.t000444000765000024 140412752350155 17441 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 60-functions.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/60-functions.t $ # use strict; use warnings; use Test::More tests => 1; use lib qw(t/lib); use Text::Sass Functions => [qw(special)]; my $scss = <<'EOT'; $string: bla $color: #ffffff li background: darken($color, 10%) content: funky($string) EOT my $css = <<'EOT'; li { background: #e5e5e5; content: funky bla; } EOT { my $ts = Text::Sass->new(); is($ts->sass2css($scss), $css, "custom function"); } Text-Sass-v1.0.4/t/60-functions.t000444000765000024 505112752350155 15645 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 60-functions.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/60-functions.t $ # use strict; use warnings; use Text::Sass; use Test::More tests => 39; use_ok('Text::Sass::Functions'); # $Text::Sass::DEBUG = 1; my $cf = 'Text::Sass::Functions'; { isa_ok($cf, 'Text::Sass::Functions'); ok($cf->can('darken'),'can darken'); } # RGB { is($cf->rgb(10,10,10), '#0a0a0a', 'rgb'); # rgba is($cf->red('#806040'), 128, 'red'); is($cf->green('#806040'), 96, 'green'); is($cf->blue('#806040'), 64, 'blue'); is($cf->mix('#f00', '#00f'), '#7f007f', 'mix 1'); is($cf->mix('#f00', '#00f', '25%'), '#3f00bf', 'mix 2'); } # HSL { is($cf->hsl(90,'50%','50%'), '#7fbf3f', 'hsl'); # hsla is($cf->hue('#7fbf3f'), 90, 'hue'); is((sprintf q[%0.2f], $cf->saturation('#7fbf3f')), (sprintf q[%0.2f], 0.503937007874016), 'saturation'); is((sprintf q[%0.2f], $cf->lightness('#7fbf3f')), (sprintf q[%0.2f], 0.498039215686275), 'lightness'); is($cf->adjust_hue('#811', 45), '#886a10', 'adjust-hue'); is($cf->lighten('#800', '20%'), '#ee0000', 'lighten'); is($cf->darken('#3bbfce', '9%'), '#2ba1af', 'darken 1'); is($cf->darken('#800', '20%'), '#220000', 'darken 2'); is($cf->saturate('#855', '20%'), '#9e3e3e', 'saturate'); is($cf->desaturate('#855', '20%'), '#716b6b', 'desaturate'); is($cf->grayscale('#855'), $cf->desaturate('#855', '100%'), 'grayscale'); is($cf->complement('#f00'), $cf->adjust_hue('#f00', 180), 'complement'); } # String { is($cf->unquote('"foo"'), 'foo', 'unquote 1'); is($cf->unquote('foo'), 'foo', 'unquote 2'); is($cf->quote('"foo"'), '"foo"', 'quote 1'); is($cf->quote('foo'), '"foo"', 'quote 2'); } # Numbers { is($cf->percentage(2), '200%', 'percentage'); is($cf->round('10.4px'), '10px', 'round 1'); is($cf->round('10.6px'), '11px', 'round 2'); is($cf->ceil('10.4px'), '11px', 'ceil 1'); is($cf->ceil('10.6px'), '11px', 'ceil 2'); is($cf->floor('10.4px'), '10px', 'floor 1'); is($cf->floor('10.6px'), '10px', 'floor 2'); is($cf->abs('10px'), '10px', 'abs 1'); is($cf->abs('-10px'), '10px', 'abs 2'); } # Introspective { is($cf->unit(100), '""', 'unit 1'); is($cf->unit('100px'), '"px"', 'unit 2'); is($cf->unit('3em'), '"em"', 'unit 3'); ok($cf->unitless(100), 'unitless 1'); ok(!$cf->unitless('100px'), 'unitless 2'); } Text-Sass-v1.0.4/t/61-keyword-arguments.t000444000765000024 123612752350155 17326 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### use strict; use warnings; use Text::Sass; use Test::More tests => 2; # TODO: Check whole CSS when keyword arguments are implemented { my $scss = <<'EOT'; $s: bla; li { content: quote($string: $s); } EOT my $ts = Text::Sass->new(); like($ts->scss2css($scss), qr/\bbla\b/, "variable substitution in keyword argument"); } { my $scss = <<'EOT'; $s: bla; li { content: quote($string:$s); } EOT my $ts = Text::Sass->new(); like($ts->scss2css($scss), qr/\bbla\b/, "variable substitution in keyword argument after missing space"); } Text-Sass-v1.0.4/t/62-nested-calls.t000444000765000024 133612752350155 16217 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### use strict; use warnings; use Text::Sass; use Test::More tests => 2; { my $scss = <<'EOT'; li { background: darken(darken(#3bbfce, 9%), 1%); } EOT SKIP: { skip "Nested function calls don't work", 1; my $ts = Text::Sass->new(); like($ts->scss2css($scss), qr/\Qbackground: #299daa;\E/, "nested function calls"); } } { my $scss = <<'EOT'; $blue: #3bbfce; $darkBlue: darken($blue, 9%); li { background: darken($darkBlue, 1%); } EOT my $ts = Text::Sass->new(); like($ts->scss2css($scss), qr/\Qbackground: #299daa;\E/, "nested function calls created via intermediate variable"); } Text-Sass-v1.0.4/t/81-sass-ex.t000444000765000024 467712752350155 15240 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 81-sass-ex.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/81-sass-ex.t $ # use strict; use warnings; use Text::Sass; use Test::More tests => 4; # $Text::Sass::DEBUG = 1; { my $css = <new(); is($ts->sass2css($sass), $css, "variables examples"); } { my $sass = <new(); is($ts->sass2css($sass), $css, "nesting example"); } { my $sass = <new(); # BOS: This looks like is wrongly implemented in sass-lang.com/try.html as well. local $TODO = "no support for extend yet"; is($ts->sass2css($sass), $css, "inherintance example"); } { my $sass = <new(); #local $TODO = "no support for extend yet"; is($ts->sass2css($sass), $css, "mixin example"); } Text-Sass-v1.0.4/t/82-sass-ex.t000444000765000024 455712752350155 15236 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 82-sass-ex.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/82-sass-ex.t $ # use strict; use warnings; use Text::Sass; use Test::More tests => 4; # $Text::Sass::DEBUG = 1; { my $css = <new(); is($ts->scss2css($scss), $css, "variables examples"); } { my $css = <new(); is($ts->scss2css($scss), $css, "nested example"); } { my $scss = <new(); is($ts->scss2css($scss), $css, "mixin example"); } { my $scss = <new(); is($ts->scss2css($scss), $css, "Selector Inheritance example"); } Text-Sass-v1.0.4/t/90-regression-aa-74181.t000444000765000024 232012752350155 17055 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-11-10 16:33:37 +0000 (Sat, 10 Nov 2012) $ # Id: $Id: 90-regression-aa-74181.t 75 2012-11-10 16:33:37Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/90-regression-aa-74181.t $ # use strict; use warnings; use Text::Sass '0.97'; use Test::More tests => 2; { my $css = <new(); is($ts->scss2css($scss), $css, "simple parent reference"); } { my $css = <new(); is($ts->scss2css($scss), $css, "complex parent reference"); } Text-Sass-v1.0.4/t/90-regression-aa.t000444000765000024 133312752350155 16376 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 90-regression-aa.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/90-regression-aa.t $ # use strict; use warnings; use Text::Sass '0.94'; use Test::More tests => 1; { my $css = <new(); is($ts->scss2css($scss), $css, "scss to css conversion ok"); } Text-Sass-v1.0.4/t/90-regression-background.t000444000765000024 363612752350155 20144 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 90-regression-background.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/90-regression-background.t $ # use strict; use warnings; use Text::Sass; use Test::More tests => 5; { my $scss = q[.x-panel-body { background: white url(/images/RegH_logo_RGB.gif) no-repeat; }]; my $ts = Text::Sass->new; is($ts->scss2css($scss), <<'EOT', 'local background + colour'); .x-panel-body { background: white url(/images/RegH_logo_RGB.gif) no-repeat; } EOT } { my $scss = q[.x-panel-body { background: url(/images/RegH_logo_RGB.gif) no-repeat; }]; my $ts = Text::Sass->new; is($ts->scss2css($scss), <<'EOT', 'local background'); .x-panel-body { background: url(/images/RegH_logo_RGB.gif) no-repeat; } EOT } { my $scss = q[.x-panel-body { background: url(http://images/RegH_logo_RGB.gif) no-repeat; }]; my $ts = Text::Sass->new; is($ts->scss2css($scss), <<'EOT', 'http/remote background'); .x-panel-body { background: url(http://images/RegH_logo_RGB.gif) no-repeat; } EOT } { my $scss = q[.x-panel-body { background: url("http://images/RegH_logo_RGB.gif") no-repeat; }]; my $ts = Text::Sass->new; is($ts->scss2css($scss), <<'EOT', 'http remote background, double-quoted'); .x-panel-body { background: url("http://images/RegH_logo_RGB.gif") no-repeat; } EOT } { my $scss = q[.x-panel-body { background: url('https://images/RegH_logo_RGB.gif') no-repeat 0 0; }]; my $ts = Text::Sass->new; is($ts->scss2css($scss), <<'EOT', 'https remote background, single-quoted'); .x-panel-body { background: url('https://images/RegH_logo_RGB.gif') no-repeat 0 0; } EOT } Text-Sass-v1.0.4/t/90-regression-bos.t000444000765000024 174512752350155 16607 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 90-regression-bos.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/90-regression-bos.t $ # use strict; use warnings; use Text::Sass '0.5'; use Test::More tests => 4; { my $css = <new(); is($ts->css2sass($css), $sass, "css to sass conversion ok"); is($ts->sass2css($sass), $css, "sass to css conversion ok"); } { my $css = <new(); # $Text::Sass::DEBUG = 1; is($ts->css2sass($css), $sass, "css to sass conversion ok"); is($ts->sass2css($sass), $css, "sass to css conversion ok"); } Text-Sass-v1.0.4/t/90-regression-wikipedia-nowhitespace.t000444000765000024 166212752350155 22457 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 90-regression-wikipedia-nowhitespace.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/90-regression-wikipedia-nowhitespace.t $ # use strict; use warnings; use Test::More tests => 1; use Text::Sass; my $sass = <new; is($ts->sass2css($sass), $css, 'wikipedia example 1'); Text-Sass-v1.0.4/t/90-regression-wikipedia-parentref.t000444000765000024 140412752350155 21746 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 90-regression-wikipedia-parentref.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/90-regression-wikipedia-parentref.t $ # use strict; use warnings; use Test::More tests => 1; use Text::Sass; my $sass = <new; is($ts->sass2css($sass), $css, 'wikipedia example parent "&" reference'); Text-Sass-v1.0.4/t/90-regression-wikipedia.t000444000765000024 163212752350155 17765 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 90-regression-wikipedia.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/90-regression-wikipedia.t $ # use strict; use warnings; use Test::More tests => 1; use Text::Sass; my $sass = <new; is($ts->sass2css($sass), $css, 'wikipedia example 1'); Text-Sass-v1.0.4/t/91-keep-order.t000444000765000024 172612752350155 15703 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 91-keep-order.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/91-keep-order.t $ # use strict; use warnings; use Text::Sass; use Test::More tests => 2; # $Text::Sass::DEBUG = 1; { my $css = <new(); is($ts->sass2css($sass), $css, "sass to css conversion ok"); } { my $css = <new(); is($ts->sass2css($sass), $css, "sass to css conversion ok"); } Text-Sass-v1.0.4/t/92-no-whitespace.t000444000765000024 124712752350155 16413 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 92-no-whitespace.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/92-no-whitespace.t $ # use strict; use warnings; use Text::Sass; use Test::More tests => 1; { my $css = <new(); is($ts->sass2css($sass), $css, "sass to css conversion ok"); } Text-Sass-v1.0.4/t/93-parentref-comma.t000444000765000024 203512752350155 16722 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: 93-parentref-comma.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/93-parentref-comma.t $ # use strict; use warnings; use Text::Sass; use Test::More tests => 1; { our $TODO = "Parent ref with commas not working"; my $css = <new(); is($ts->sass2css($sass), $css, "sass to css conversion ok"); } } Text-Sass-v1.0.4/t/94-scss-linebreaks.t000444000765000024 276712752350155 16747 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### use strict; use warnings; use Text::Sass; use Test::More tests => 6; # $Text::Sass::DEBUG = 1; my $css = <<'EOT'; .border { margin: 16px; } EOT { my $scss = <<'EOT'; $margin : 16px; .border { margin: $margin; } EOT my $ts = Text::Sass->new(); is($ts->scss2css($scss), $css, "multiline scss variable declaration"); } { my $scss = <<'EOT'; $margin: 16px ; .border { margin: $margin; } EOT my $ts = Text::Sass->new(); is($ts->scss2css($scss), $css, "line break after scss variable declaration"); } { my $scss = <<'EOT'; $margin : floor(33px / 2); .border { margin: $margin; } EOT my $ts = Text::Sass->new(); is($ts->scss2css($scss), $css, "multiline scss variable declaration with function call"); } { my $scss = <<'EOT'; .border { margin: 16px ; } EOT my $ts = Text::Sass->new(); is($ts->scss2css($scss), $css, "line break in simple property declaration"); } # This snippet was causing infinite loop { my $scss = <<'EOT'; $margin: 16px; .border { margin: $margin; } EOT my $ts = Text::Sass->new(); is($ts->scss2css($scss), $css, "line break in property declaration with variable"); } { my $scss = <<'EOT'; $margin: 16px; .title { margin: foo( $margin: 1 ); } .border { margin: $margin; } EOT my $ts = Text::Sass->new(); like($ts->scss2css($scss), qr/\Q$css\E/, "line break in property declaration with variable"); } Text-Sass-v1.0.4/t/RT-62474-accept-spaces.t000444000765000024 204112752350155 17130 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-09-12 09:42:30 +0100 (Wed, 12 Sep 2012) $ # Id: $Id: RT-62474-accept-spaces.t 71 2012-09-12 08:42:30Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/RT-62474-accept-spaces.t $ # use strict; use warnings; use Text::Sass; use Test::More tests => 3; use Try::Tiny; { my $css = <new(); is($ts->sass2css($sass), $css, "sass to css conversion ok"); } { my $css = <new(); is($ts->sass2css($sass), $css, "sass to css conversion ok"); } { my $sass = <new(); try { diag $ts->sass2css($sass); } catch { ok(1, "dieing from illegal indent $_"); } }Text-Sass-v1.0.4/t/RT-80831-commasep-selectors.t000444000765000024 134312752350155 20223 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-11-10 16:33:37 +0000 (Sat, 10 Nov 2012) $ # Id: $Id: RT-80831-commasep-selectors.t 75 2012-11-10 16:33:37Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/RT-80831-commasep-selectors.t $ # use strict; use warnings; use Text::Sass; use Test::More tests => 1; { my $sass = <new(); is($ts->scss2css($sass), $css, "RT#80831 scss to css for comma-separated selectors"); } Text-Sass-v1.0.4/t/RT-80927-nested-includes.t000444000765000024 144212752350155 17512 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-11-10 16:33:37 +0000 (Sat, 10 Nov 2012) $ # Id: $Id: RT-80927-nested-includes.t 75 2012-11-10 16:33:37Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/RT-80927-nested-includes.t $ # use strict; use warnings; use Text::Sass; use Test::More tests => 1; { my $sass = <<'EOT'; @mixin test { color: #fff; } p { .a { .b { @include test; } } .c { @include test; } } EOT my $css = <new(); is($ts->scss2css($sass), $css, "RT#80927 scss to css for nested includes"); } Text-Sass-v1.0.4/t/RT-80978-nested-ampersand-includes.t000444000765000024 145112752350155 21470 0ustar00rmpstaff000000000000# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*- # vim:ts=8:sw=2:et:sta:sts=2 ######### # Author: rmp # Last Modified: $Date: 2012-11-10 16:33:37 +0000 (Sat, 10 Nov 2012) $ # Id: $Id: RT-80978-nested-ampersand-includes.t 75 2012-11-10 16:33:37Z zerojinx $ # $HeadURL: https://text-sass.svn.sourceforge.net/svnroot/text-sass/trunk/t/RT-80978-nested-ampersand-includes.t $ # use strict; use warnings; use Text::Sass; use Test::More tests => 1; { my $sass = <<'EOT'; a { b { &.this { color: #fff; } } } EOT my $css = <new(); is($ts->scss2css($sass), $css, "RT#80978 scss to css for nested ampersand includes"); } } Text-Sass-v1.0.4/t/lib000755000765000024 012752350155 13635 5ustar00rmpstaff000000000000Text-Sass-v1.0.4/t/lib/special.pm000444000765000024 15412752350155 15730 0ustar00rmpstaff000000000000package special; use strict; use warnings; sub funky { my ($class, $str) = @_; return "funky $str"; }; 1;