csspress 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,7 @@
1
+ == 0.0.4 2008-05-20
2
+
3
+ * Major re-factoring. This has made the classes lighter. Testing has also been improved.
4
+
1
5
  == 0.0.3 2008-05-18
2
6
 
3
7
  * Fixed -h flag bug
data/Manifest.txt CHANGED
@@ -11,6 +11,7 @@ lib/csspress.rb
11
11
  lib/csspress/declaration.rb
12
12
  lib/csspress/rule.rb
13
13
  lib/csspress/style_sheet.rb
14
+ lib/csspress/style_sheet_parser.rb
14
15
  lib/csspress/template_builder.rb
15
16
  lib/csspress/version.rb
16
17
  lib/templates/default.csst
@@ -20,8 +21,13 @@ script/generate
20
21
  script/txt2html
21
22
  setup.rb
22
23
  spec/csspress_spec.rb
24
+ spec/declaration_spec.rb
25
+ spec/rule_spec.rb
23
26
  spec/spec.opts
24
27
  spec/spec_helper.rb
28
+ spec/style_sheet_spec.rb
29
+ spec/style_sheet_parser_spec.rb
30
+ spec/template_builder_spec.rb
25
31
  tasks/custom.rake
26
32
  tasks/deployment.rake
27
33
  tasks/environment.rake
data/PostInstall.txt CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- For more information on csspress, see http://csspress.rubyforge.org
2
+ For more information on csspress, see http://www.csspress.net
3
3
 
4
4
 
5
5
  To get cracking straight away:
data/README.txt CHANGED
@@ -1,13 +1,13 @@
1
- = csspress
1
+ = CSSpress
2
2
 
3
3
  Project Page:
4
- - http://csspress.rubyforge.org
4
+ - http://www.csspress.net
5
5
  RubyForge Page:
6
6
  - http://rubyforge.org/projects/csspress/
7
7
 
8
8
  == DESCRIPTION:
9
9
 
10
- Press out only the juice worth serving from you CSS files (and optimize it a little while your at it).
10
+ Press out only the juice worth serving from your CSS files (and optimize it a little while your at it).
11
11
 
12
12
  When you are building a website, a well formatted and clearly commented CSS file can make it really easy
13
13
  for developers to see what is going on and build beautiful pages. All of this extra stuff however needs to be downloaded by a end user who is never going to read it, but has to wait for it.
data/bin/css CHANGED
@@ -29,11 +29,9 @@
29
29
  # == Options
30
30
  # -h, --help Displays help message
31
31
  # -s, --stats Output compression information
32
- # -v, --version Display the version, then exit
33
- #
34
- # == Author
35
- # David Madden
32
+ # -v, --version Display the version
36
33
  #
34
+
37
35
  require 'optparse' # for parsing cmd line options
38
36
  require 'rdoc/usage' # for outputing rdoc to terminal
39
37
  require 'ostruct' # useful in cmd line option usage
@@ -139,32 +137,26 @@ class App #:nodoc: all
139
137
  # and output that file to pressed_filename.css
140
138
  #
141
139
  def process_command
142
- begin
143
- file_in = @arguments[0]
144
- # Get the dir
145
- path = File.dirname(file_in)
146
- # Get the file name
147
- name = File.basename(file_in)
148
-
149
- # Create name for tar file
150
- file_out = "csspress-" << name.dup
151
-
152
- # Do the compression stuff
153
- ss = StyleSheet.new
154
- ss.load( file_in )
155
- tb = TemplateBuilder.new( ss )
156
-
157
- # Change working dir to files dir
158
- Dir.chdir(path)
159
-
160
- out = File.new( file_out, "w" )
161
- out.write(tb.publish)
162
- out.close
163
- rescue Declaration::PropertyError => e
164
- puts e
165
- rescue IOError => e
166
- puts e
167
- end
140
+ file_in = @arguments[0]
141
+ # Get the dir
142
+ path = File.dirname(file_in)
143
+ # Get the file name
144
+ name = File.basename(file_in)
145
+
146
+ # Create name for tar file
147
+ file_out = path <<"/csspress-" << name
148
+
149
+ # Do the compression stuff
150
+ ssp = StyleSheetParser.new( file_in )
151
+ ss = ssp.style_sheet
152
+ tb = TemplateBuilder.new( ss )
153
+
154
+ # Change working dir to files dir
155
+ #Dir.chdir(path)
156
+
157
+ out = File.new( file_out, "w" )
158
+ out.write(tb.publish)
159
+ out.close
168
160
  output_stats(file_in, file_out) if @options.stats
169
161
  #process_standard_input # [Optional]
170
162
  end
data/lib/csspress.rb CHANGED
@@ -13,6 +13,7 @@ $:.unshift(File.dirname(__FILE__)) unless
13
13
  require "csspress/declaration"
14
14
  require "csspress/rule"
15
15
  require "csspress/style_sheet"
16
+ require "csspress/style_sheet_parser"
16
17
  require "csspress/template_builder"
17
18
  require "csspress/version"
18
19
 
@@ -11,24 +11,18 @@
11
11
  # It is composed of a property and a value. The property must be
12
12
  # valid.
13
13
  #
14
- # Declaration takes a string and populates itself.
15
14
  #
16
15
  # Example:
17
- # d = declaration.new ( "border-color : blue" )
16
+ # d = declaration.new ( "border-color", "blue" )
18
17
  # puts d.property #=> "border-color"
19
18
  # puts d.value #=> "blue"
20
19
  #
21
20
  class Declaration
22
21
 
23
- # Declaration property
24
- attr_reader :property
25
- # Declaration value
26
- attr_reader :value
22
+ attr_reader :property, :value
27
23
 
28
- # internal error for invalid property types
29
- #
30
- class PropertyError < StandardError
31
- # do nothing - just creating a specific error
24
+ class PropertyError < StandardError #:nodoc:
25
+ # do nothing - just creating an error for internal use
32
26
  end
33
27
 
34
28
  # Properties for CSS1 to CSS3
@@ -64,81 +58,14 @@ class Declaration
64
58
  white-space white-space-collapse widows width word-break word-spacing word-wrap z-index
65
59
  )
66
60
 
67
- ## Create a new Declaration from a string
68
- # (The string should be valid CSS!)
69
- #
70
- def initialize(text)
71
- dp = DeclarationParser.new(text)
72
- @property = dp.property
73
- @value = dp.value
61
+ def initialize(property, value)
62
+ raise PropertyError unless VALID_PROPERTIES.include?(property)
63
+ @property = property
64
+ @value = value
74
65
  end
75
66
 
76
- # Print out the rule neatly
77
- #
78
67
  def to_s
79
- "#{@property}:#{@value}"
68
+ "#{@property}:#{@value}"
80
69
  end
81
70
 
82
- private
83
-
84
- # This class parses the text entered and makes the
85
- # property and value available to the Declaration that
86
- # initialised it.
87
- #
88
- class DeclarationParser #:nodoc:
89
- attr_reader :property, :value
90
-
91
- def initialize(raw_data)
92
- @raw_data = raw_data
93
- @property = ""
94
- @value = ""
95
- parse
96
- end
97
-
98
- private
99
-
100
- # Call methods to parse @raw_data and
101
- # extract the property and name.
102
- #
103
- # Raise an error if the property found
104
- # is invalid.
105
- #
106
- def parse
107
- @property = get_property
108
- raise PropertyError, "Invalid property type found: #{@property}" unless VALID_PROPERTIES.include? @property
109
- @value = get_value
110
- end
111
-
112
- # Get the property from @raw_data
113
- #---
114
- # The property is the part of @raw_data
115
- # before the ':' character.
116
- #+++
117
- #
118
- def get_property
119
- @raw_data.slice(0, @raw_data.index(":")).strip
120
- end
121
-
122
- # Get the value from @raw_data
123
- #---
124
- # The value is the part of @raw_data
125
- # after the ':' character.
126
- #+++
127
- #
128
- def get_value
129
- @raw_data.slice(@raw_data.index(":")+1..@raw_data.size-1).strip
130
- end
131
- end
132
- end
133
-
134
-
135
-
136
- if __FILE__ == $0
137
- begin
138
- d = Declaration.new("backgrond-color: sdfds")
139
- puts d.property
140
- puts d.value
141
- rescue PropertyError => e
142
- puts e.message
143
- end
144
71
  end
data/lib/csspress/rule.rb CHANGED
@@ -12,112 +12,55 @@
12
12
  # body { margin : 0; padding : 0 }
13
13
  #
14
14
  # The components of a rule are:
15
- # name { declarations }
15
+ # name { declaration block }
16
16
  #
17
17
  # All declarations of Rule can be accessed using the
18
18
  # .each_declaration(){} method where each declaration
19
- # is passed to the block as a Declaration object.
19
+ # is passed to the block.
20
20
  #
21
21
  # Example:
22
- # r = Rule.new ( "foo { margin: 0; padding: 0 }" )
22
+ # r = Rule.new ( "my rule" )
23
+ # r.add(Declaration.new("margin", "1px"))
23
24
  # r.each_declaration do |dec|
24
25
  # puts dec
25
26
  # end
26
27
  # puts r.name
27
- #
28
+ #
28
29
  class Rule
29
30
 
30
- # name of the Rule
31
31
  attr_reader :name
32
- # declarations contained within Rule
33
- attr_reader :declarations
34
32
 
35
- # Create a new Rule from a string
36
- # (The string should be a valid CSS rule!)
33
+ # Create a new Rule with name
34
+ #
35
+ def initialize(name)
36
+ @name = name
37
+ @declaration_block = []
38
+ end
39
+
40
+ # add a Declaration to the rule's declaration block
37
41
  #
38
- def initialize( string )
39
- rp = RuleParser.new( string )
40
- @name = rp.name
41
- @declarations = rp.declarations
42
+ def add(declaration)
43
+ raise ArgumentError unless declaration.instance_of?(Declaration)
44
+ @declaration_block << declaration
42
45
  end
43
46
 
44
- # Yeild all declarations for self
47
+ # iterate through the declarations in the declaration block and pass
48
+ # each one to the block
45
49
  #
46
50
  def each_declaration
47
- @declarations.each do |declaration|
51
+ @declaration_block.each do |declaration|
48
52
  yield declaration
49
53
  end
50
54
  end
51
55
 
52
- # Print out the rule neatly
56
+ # Return all declarations for the rule in an array
53
57
  #
54
- def to_s
55
- "#{@name}{#{@declarations.join(";")}}"
58
+ def declaration_block
59
+ @declaration_block.dup
56
60
  end
57
61
 
58
- private
59
-
60
- # This class parses the text entered and makes the
61
- # name and declarations available to the Rule that
62
- # initialised it.
63
- #
64
- class RuleParser #:nodoc:
65
-
66
- attr_reader :name, :declarations
67
-
68
- # Create a new RuleParser and parse raw_data
69
- #
70
- def initialize( raw_data )
71
- @raw_data = raw_data
72
- @name = ""
73
- @declarations = []
74
- parse
75
- end
76
-
77
- private
78
-
79
- # Calls the methods needed to retrieve the
80
- # information from @raw_data
81
- #
82
- def parse
83
- @name = get_rule_name
84
- @declarations = get_declarations
85
- end
86
-
87
- # Get the name of the rule from @raw_data
88
- #---
89
- # Simply a case of cutting the front off the
90
- # @raw data string up to the first '{' and
91
- # remove any white space
92
- # +++
93
- #
94
- def get_rule_name
95
- @raw_data.slice(0, @raw_data.index("{")).strip
96
- end
97
-
98
- # Get an array of declartaions for the Rule.
99
- #---
100
- # Get the part of @raw_data between '{'..'}'
101
- # This is all of the declaration text.
102
- # Declarations are delimeted by ';' so
103
- # the string is split on the semi-colon and
104
- # a new Declaration object is created for each
105
- # one.
106
- #+++
107
- #
108
- def get_declarations
109
- tmp = []
110
- raw = @raw_data.slice(@raw_data.index("{")+1..@raw_data.index("}")-1).strip
111
- raw.split(";").each do |line|
112
- tmp << Declaration.new(line.strip)
113
- end
114
- tmp
115
- end
62
+ def to_s
63
+ "#{@name}{#{@declaration_block.join(";")}}"
116
64
  end
117
- end
118
-
119
- if __FILE__ == $0
120
- r = Rule.new("this is a test { background-color: sdfds; color:adlkasdj}")
121
- puts r.name
122
- puts r.declarations
65
+
123
66
  end
@@ -1,6 +1,6 @@
1
1
  #!/usr/local/bin/ruby -w
2
2
 
3
- # style_sheet.rb
3
+ # style_sheet_parser.rb
4
4
  #
5
5
  # Created by David Madden on 2008-05-14.
6
6
  # Copyright 2008 David Madden. All rights reserved.
@@ -12,232 +12,48 @@
12
12
  # contains can be accessed using the .each_rule(){} method which yields
13
13
  # each Rule to the block.
14
14
  #
15
- # StyleSheet can also accept a CSS file as a paramiter to .new or using the
16
- # .load() method. This file is then converted into Rule objects and they are
17
- # added to StyleSheet. A compressed version of StyleSheet can be output using
18
- # a TemplateBuilder object and passing it StyleSheet as a parameter.
19
- #
20
15
  # Example:
21
- # ss = StyleSheet.new ( "foo.css" )
16
+ # ss = StyleSheet.new
17
+ # ss.add( Rule.new("A Rule") )
22
18
  # tb = TemplateBuilder.new ( ss )
23
19
  # puts tb.publish # output compressed version of ss
24
- #
20
+ #
25
21
  class StyleSheet
26
22
 
27
- # rule objects
28
- #---
29
- # TODO: remove this and only allow access through each_rule.
30
- # +++
31
- attr_reader :rules
32
-
33
- # Creates a new StyleSheet object. Can also accept a file name
34
- # and parse the contents to initalize the StyleSheet with the file's
35
- # contents.
36
- #
37
- def initialize(file=nil)
23
+ def initialize
24
+ # Store style rules in order
38
25
  @rules = []
39
- load file unless file.nil?
40
- end
41
-
42
- # Yeild each style rule in self
43
- #
44
- def each_rule
45
- @rules.each do |rule|
46
- yield rule
47
- end
48
26
  end
49
27
 
50
- # Output a compressed version of self
51
- #
52
- #def compress
53
- # out = ""
54
- # self.each_style do |rule|
55
- # out << rule.compress
56
- # end
57
- # out
58
- #end
59
-
60
- # Load a CSS file into self
61
- #
62
- def load(file)
63
- ssp = StyleSheetParser.new(file)
64
- ssp.each { |rule| add(rule) }
65
- end
66
-
67
- # Add a rule to self
68
- #
28
+ # Add rule to StyleSheet
29
+ # Raises ArgumentError rule is not a Rule
69
30
  def add(rule)
70
- @rules << Rule.new(rule)
71
- self
31
+ raise ArgumentError unless rule.instance_of?(Rule)
32
+ @rules << rule
33
+ @self
72
34
  end
73
35
 
74
- # Output self as String
75
- #
76
- def to_s
77
- out = ""
78
- self.each_rule do |rule|
79
- out << "#{rule}\n"
80
- end
81
- out
82
- end
83
-
84
- # Number of Rules in Self
85
- #
36
+ # The number of rules in self
86
37
  def size
87
38
  @rules.size
88
39
  end
89
40
 
90
- # Alias of size
91
- #
92
- def length
93
- size
41
+ # Iterate through all rules in self and yield them
42
+ # to a block
43
+ def each_rule
44
+ @rules.each {|r| yield r }
94
45
  end
95
46
 
96
- private
47
+ # Return an array of all rules in self
48
+ def rules
49
+ @rules.dup
50
+ end
97
51
 
98
- # This class is responsible for processing a CSS file
99
- # and allows iteration over the rules contained within
100
- # the file to add to a StyleSheet object.
101
- #--
102
- # Due to the flexible nature of CSS syntax most of the
103
- # work performed by the parser is envolved in normalizing
104
- # the text into an array of style rules with the
105
- # comments striped out.
106
- #
107
- # This parser uses patern matching and string manupulation
108
- # rather than analysing the file byte, by byte. This may or
109
- # may not be proved to be a good thing.
110
- #
111
- # At present all '@import' statements with in the CSS file are
112
- # ignored!
113
- #
114
- # A file is processed as follows:
115
- # 1. The file is read into an array (@raw_data)
116
- # 2. White space is removed from the beginnig and end of each field in the @raw_data
117
- # 3. Comments are sepatated into there own array fields as they could be mixed into style code
118
- # 4. All fields with comments and empty fields are removed from @raw_data
119
- # 5. All style rules are put in their own array field
120
- # 6. Each field has any white space removed
121
- # Data clean!
122
- #
123
- # Only the file in gerneral is parsed. Parsing of Rules and Declarations
124
- # is handled by them internaly.
125
- #++
126
- #
127
- class StyleSheetParser #:nodoc:
128
- attr_reader :lines
129
-
130
- # Creates new StyleSheetParser to parse the file
131
- # file_name
132
- #
133
- def initialize( file_name )
134
- @file = file_name
135
- @raw_data = []
136
- parse
137
- end
138
-
139
- # Yield each rule in the parsed file
140
- #
141
- def each
142
- @raw_data.each do |rule|
143
- yield rule
144
- end
145
- end
146
-
147
- private
148
-
149
- # Controls the processing of the data by calling
150
- # a number of private functions.
151
- #
152
- # The order of the method calls is important and
153
- # the successful removal of comments depends
154
- # upon it!
155
- #
156
- def parse
157
- get_lines
158
- remove_white_space
159
- separate_comments
160
- delete_comments_and_blank_lines
161
- separate_rules
162
- remove_white_space
163
- end
164
-
165
- # Read in all lines of @file to @raw_data.
166
- # Will raise an error if there is any problem with
167
- # accessing the file.
168
- #
169
- def get_lines
170
- begin
171
- f = File.open( @file, 'r' )
172
- @raw_data = f.readlines
173
- rescue
174
- raise IOError, "Could not process file: #{@file}"
175
- ensure
176
- f.close unless f.nil?
177
- end
178
- end
179
-
180
- # This removes white space from the beginning
181
- # and end of every field in the @raw_data array,
182
- # as well as removing runs of space characters.
183
- #
184
- def remove_white_space
185
- @raw_data.each do |line|
186
- line.strip! # remove white space from line beginnig and end
187
- line.squeeze!( " " ) # remove runs of spaces
188
- end
189
- end
190
-
191
- # Put a linebreak before and after every comment
192
- # in @raw_data
193
- #
194
- def separate_comments
195
- tmp = @raw_data.join(" ") # convert to string
196
- tmp.gsub!( '/*', "\n/*" ) # add new line before comment
197
- tmp.gsub!( '*/', "*/\n" ) # add new line after comment
198
- @raw_data = tmp.split( "\n" ) # convert to array
199
- end
200
-
201
- # Remove comments and blank lines from @raw_data.
202
- #
203
- # This method currently also removes import stetments.
204
- # TODO: move import handleing to separate method.
205
- #
206
- def delete_comments_and_blank_lines
207
- tmp = []
208
- @raw_data.each do |line|
209
- line.strip! # remove any white space
210
- next if line.length < 1 # ignore blank line
211
- next if line =~ /\/\*/ # ignore comments
212
- next if line =~ /import/ # ignore imports specially
213
- tmp << line
214
- end
215
- @raw_data = tmp
52
+ def to_s
53
+ out = ""
54
+ @rules.each do |rule|
55
+ out << rule.to_s
216
56
  end
217
-
218
- # Add a new line character after every style rule
219
- # in @raw_data
220
- #
221
- def separate_rules
222
- tmp = @raw_data.join( " " ) # convert to string
223
- tmp.gsub!( '}', "}\n" ) # add a new line after every style rule
224
- @raw_data = tmp.split( "\n" ) # convert to array
225
- end
226
- end
227
- end
228
-
229
-
230
- if __FILE__ == $0
231
- begin
232
- ss = StyleSheet.new( "../test_data/style.css" )
233
- #ss.load( "../test_data/style.css" )
234
- tb = TemplateBuilder.new(ss)
235
- puts tb.publish
236
- rescue Declaration::PropertyError => e
237
- puts e
238
- rescue IOError => e
239
- puts e
240
- rescue Error => e
241
- puts e
57
+ out
242
58
  end
243
59
  end
@@ -0,0 +1,287 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # style_sheet.rb
4
+ #
5
+ # Created by David Madden on 2008-05-14.
6
+ # Copyright 2008 David Madden. All rights reserved.
7
+ #
8
+ # This is Free Software. See LICENSE for details.
9
+
10
+ # This class is responsible for processing a CSS file.
11
+ # It creates a StyleSheet object from the content of the file.
12
+ # The StyleSheet can be obtained using the style_sheet() method.
13
+ #
14
+ # Example:
15
+ # ssp = StyleSheetParser("foo.css")
16
+ # stylesheet = ssp.style_sheet
17
+ # puts stylesheet
18
+ #
19
+ #--
20
+ # Due to the flexible nature of CSS syntax most of the
21
+ # work performed by the parser is envolved in normalizing
22
+ # the text into an array of style rules with the
23
+ # comments striped out.
24
+ #
25
+ # This parser uses patern matching and string manupulation
26
+ # rather than analysing the file byte, by byte. This may or
27
+ # may not be proved to be a good thing.
28
+ #
29
+ # At present all '@import' statements with in the CSS file are
30
+ # ignored!
31
+ #
32
+ # A file is processed as follows:
33
+ # 1. The file is read into an array (@raw_data)
34
+ # 2. White space is removed from the beginnig and end of each field in the @raw_data
35
+ # 3. Comments are sepatated into there own array fields as they could be mixed into style code
36
+ # 4. All fields with comments and empty fields are removed from @raw_data
37
+ # 5. All style rules are put in their own array field
38
+ # 6. Each field has any white space removed
39
+ # 7. A style sheet object is populated with the parsed rules
40
+ # Data clean!
41
+ #
42
+ # Only the file in gerneral is parsed. Parsing of Rules and Declarations
43
+ # is handled by internaly by nested classes. StyleSheet parser breaks a
44
+ # file down into indevidule rules. It then uses a RuleParse object to parse
45
+ # each of these rules. The rule parser then breaks up the rule into a name and
46
+ # declaration block. It the uses a Declaration Parser on each declaration.
47
+ #++
48
+ #
49
+ class StyleSheetParser
50
+
51
+ # Creates new StyleSheetParser to parse the file
52
+ # file
53
+ #
54
+ def initialize( file )
55
+ @file = file
56
+ @raw_data = []
57
+ @style_sheet = nil
58
+ parse
59
+ end
60
+
61
+ # Get parsed style sheet
62
+ #
63
+ def style_sheet
64
+ @style_sheet.dup
65
+ end
66
+
67
+ private
68
+
69
+ # Yield each rule in the parsed file
70
+ #
71
+ def each
72
+ @raw_data.each do |rule|
73
+ yield rule
74
+ end
75
+ end
76
+
77
+ # Controls the processing of the data by calling
78
+ # a number of private functions.
79
+ #
80
+ # The order of the method calls is important and
81
+ # the successful removal of comments depends
82
+ # upon it!
83
+ #
84
+ def parse
85
+ get_lines
86
+ remove_white_space
87
+ separate_comments
88
+ delete_comments_and_blank_lines
89
+ separate_rules
90
+ remove_white_space
91
+ populate_style_sheet
92
+ end
93
+
94
+ # Read in all lines of @file to @raw_data.
95
+ # Will raise an error if there is any problem with
96
+ # accessing the file.
97
+ #
98
+ def get_lines
99
+ begin
100
+ f = File.open( @file, 'r' )
101
+ @raw_data = f.readlines
102
+ rescue
103
+ raise IOError, "Could not process file: #{@file}"
104
+ ensure
105
+ f.close unless f.nil?
106
+ end
107
+ end
108
+
109
+ # This removes white space from the beginning
110
+ # and end of every field in the @raw_data array,
111
+ # as well as removing runs of space characters.
112
+ #
113
+ def remove_white_space
114
+ @raw_data.each do |line|
115
+ line.strip! # remove white space from line beginnig and end
116
+ line.squeeze!( " " ) # remove runs of spaces
117
+ end
118
+ end
119
+
120
+ # Put a linebreak before and after every comment
121
+ # in @raw_data
122
+ #
123
+ def separate_comments
124
+ tmp = @raw_data.join(" ") # convert to string
125
+ tmp.gsub!( '/*', "\n/*" ) # add new line before comment
126
+ tmp.gsub!( '*/', "*/\n" ) # add new line after comment
127
+ @raw_data = tmp.split( "\n" ) # convert to array
128
+ end
129
+
130
+ # Remove comments and blank lines from @raw_data.
131
+ #
132
+ # This method currently also removes import stetments.
133
+ # TODO: move import handleing to separate method.
134
+ #
135
+ def delete_comments_and_blank_lines
136
+ tmp = []
137
+ @raw_data.each do |line|
138
+ line.strip! # remove any white space
139
+ next if line.length < 1 # ignore blank line
140
+ next if line =~ /\/\*/ # ignore comments
141
+ next if line =~ /import/ # ignore imports specially
142
+ tmp << line
143
+ end
144
+ @raw_data = tmp
145
+ end
146
+
147
+ # Add a new line character after every style rule
148
+ # in @raw_data
149
+ #
150
+ def separate_rules
151
+ tmp = @raw_data.join( " " ) # convert to string
152
+ tmp.gsub!( '}', "}\n" ) # add a new line after every style rule
153
+ @raw_data = tmp.split( "\n" ) # convert to array
154
+ end
155
+
156
+ def populate_style_sheet
157
+ tmp = StyleSheet.new
158
+ each do |rule|
159
+ begin
160
+ rp = RuleParser.new(rule)
161
+ tmp.add(rp.rule)
162
+ rescue PropertyError
163
+ puts "An invalid property was detected: #{rule}"
164
+ end
165
+ end
166
+ @style_sheet = tmp
167
+ end
168
+
169
+
170
+ # This class parses the text entered and makes the
171
+ # name and declarations available to the Rule that
172
+ # initialised it.
173
+ #
174
+ class RuleParser #:nodoc:
175
+ attr_reader :rule
176
+
177
+ # Create a new RuleParser and parse raw_data
178
+ #
179
+ def initialize( raw_data )
180
+ @rule = nil
181
+ @raw_data = raw_data
182
+ @name = ""
183
+ @declarations = []
184
+ parse
185
+ end
186
+
187
+ private
188
+
189
+ # Calls the methods needed to retrieve the
190
+ # information from @raw_data
191
+ #
192
+ def parse
193
+ @name = get_rule_name
194
+ @declarations = get_declarations
195
+ @rule = Rule.new(@name)
196
+ @declarations.each {|dec| @rule.add(dec)}
197
+ end
198
+
199
+ # Get the name of the rule from @raw_data
200
+ #---
201
+ # Simply a case of cutting the front off the
202
+ # @raw data string up to the first '{' and
203
+ # remove any white space
204
+ # +++
205
+ #
206
+ def get_rule_name
207
+ @raw_data.slice(0, @raw_data.index("{")).strip
208
+ end
209
+
210
+ # Get an array of declartaions for the Rule.
211
+ #---
212
+ # Get the part of @raw_data between '{'..'}'
213
+ # This is all of the declaration text.
214
+ # Declarations are delimeted by ';' so
215
+ # the string is split on the semi-colon and
216
+ # a new Declaration object is created for each
217
+ # one.
218
+ #+++
219
+ #
220
+ def get_declarations
221
+ tmp = []
222
+ raw = @raw_data.slice(@raw_data.index("{")+1..@raw_data.index("}")-1).strip
223
+ raw.split(";").each do |line|
224
+ dp = DeclarationParser.new(line.strip)
225
+ tmp << dp.declaration
226
+ end
227
+ tmp
228
+ end
229
+ end
230
+
231
+ # This class parses the text entered and makes the
232
+ # property and value available to the Declaration that
233
+ # initialised it.
234
+ #
235
+ class DeclarationParser #:nodoc:
236
+ attr_reader :declaration
237
+
238
+ def initialize(raw_data)
239
+ @declaration = nil
240
+ @raw_data = raw_data
241
+ @property = ""
242
+ @value = ""
243
+ parse
244
+ end
245
+
246
+ private
247
+
248
+ # Call methods to parse @raw_data and
249
+ # extract the property and name.
250
+ #
251
+ # Raise an error if the property found
252
+ # is invalid.
253
+ #
254
+ def parse
255
+ @property = get_property
256
+ @value = get_value
257
+ @declaration = Declaration.new(@property, @value)
258
+ end
259
+
260
+ # Get the property from @raw_data
261
+ #---
262
+ # The property is the part of @raw_data
263
+ # before the ':' character.
264
+ #+++
265
+ #
266
+ def get_property
267
+ @raw_data.slice(0, @raw_data.index(":")).strip
268
+ end
269
+
270
+ # Get the value from @raw_data
271
+ #---
272
+ # The value is the part of @raw_data
273
+ # after the ':' character.
274
+ #+++
275
+ #
276
+ def get_value
277
+ @raw_data.slice(@raw_data.index(":")+1..@raw_data.size-1).strip
278
+ end
279
+ end
280
+ end
281
+
282
+
283
+
284
+ if __FILE__ == $0
285
+ ssp = StyleSheetParser.new("../../test/style.css")
286
+ puts ssp.style_sheet
287
+ end
@@ -29,15 +29,16 @@ require 'erb'
29
29
  class TemplateBuilder
30
30
 
31
31
  # Style sheet to publish
32
- attr_reader :style_sheet
32
+ attr_reader :style_sheet, :template
33
33
  TEMPLATE_DIR = "/../templates/"
34
- DEFAULT = "default.csst"
34
+ DEFAULT = "/../templates/default.csst"
35
35
  # Create a new TemplateBuilder for style_sheet using
36
36
  # template.
37
37
  #
38
38
  def initialize( style_sheet, template=DEFAULT )
39
+ raise ArgumentError unless style_sheet.instance_of?(StyleSheet)
39
40
  @style_sheet = style_sheet
40
- @template = File.dirname(__FILE__) + TEMPLATE_DIR + template
41
+ @template = template
41
42
  end
42
43
 
43
44
 
@@ -47,7 +48,7 @@ class TemplateBuilder
47
48
  #
48
49
  def publish
49
50
  begin
50
- template = File.read(@template)
51
+ template = File.read(File.dirname(__FILE__) + @template)
51
52
  engin = ERB.new(template)
52
53
  t = engin.result(binding())
53
54
  # Chomp the trailing newline
@@ -56,18 +57,4 @@ class TemplateBuilder
56
57
  raise IOError, "Could not use requested template file: #{@template}"
57
58
  end
58
59
  end
59
- end
60
-
61
-
62
- if __FILE__ == $0
63
-
64
- require "style_sheet"
65
-
66
- ss = StyleSheet.new
67
- ss.load( "../test_data/style.css" )
68
- tb = TemplateBuilder.new(ss, "../templates/style_sheet.cssplate")
69
- # out = File.new("../test_data/compressed_style.css", "w")
70
- # out.write(tb.publish)
71
- # out.close
72
- puts tb.publish
73
60
  end
@@ -13,7 +13,7 @@ module Csspress #:nodoc:
13
13
  module VERSION #:nodoc:
14
14
  MAJOR = 0
15
15
  MINOR = 0
16
- TINY = 3
16
+ TINY = 4
17
17
 
18
18
  STRING = [MAJOR, MINOR, TINY].join('.')
19
19
  end
@@ -1,5 +1,7 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper.rb'
2
2
 
3
- describe "Requres" do
4
-
3
+ describe Csspress do
4
+ it "should have a version" do
5
+ Csspress::VERSION::STRING.should_not be_nil
6
+ end
5
7
  end
@@ -0,0 +1,29 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe Declaration do
4
+
5
+ before(:each) do
6
+ @dec = Declaration.new("margin", "0")
7
+ end
8
+
9
+ # is everything connected?
10
+ it "should exist" do
11
+ @dec.should_not be_nil
12
+ @dec.should be_an_instance_of(Declaration)
13
+ end
14
+
15
+ it "should have a property and be readable" do
16
+ @dec.property.should_not be_nil
17
+ @dec.property.should == "margin"
18
+ end
19
+
20
+ it "should have a value and be readable" do
21
+ @dec.value.should_not be_nil
22
+ @dec.value.should == "0"
23
+ end
24
+
25
+ it "should raise a property error if property is not valid" do
26
+ lambda { dec = Declaration.new("foo", "10") }.should raise_error(Declaration::PropertyError)
27
+ end
28
+ end
29
+
data/spec/rule_spec.rb ADDED
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe Rule do
4
+
5
+ before(:each) do
6
+ @rule = Rule.new("Test Rule")
7
+ @decs = [Declaration.new("border", "1px"),Declaration.new("margin", "1px"),Declaration.new("width","2px")]
8
+ end
9
+
10
+ # is everything connected?
11
+ it "should exist" do
12
+ @rule.should_not be_nil
13
+ @rule.should be_an_instance_of(Rule)
14
+ end
15
+
16
+ it "should have a name" do
17
+ @rule.name.should_not be_nil
18
+ @rule.name.should == "Test Rule"
19
+ end
20
+
21
+ it "should allow declarations to be added" do
22
+ @rule.add(Declaration.new("height","2px"))
23
+ end
24
+
25
+ it "should only allow declarations to be added" do
26
+ lambda { @rule.add("foo") }.should raise_error(ArgumentError)
27
+ end
28
+
29
+ it "should allow iteration of the declarations" do
30
+ @decs.each {|dec| @rule.add(dec)}
31
+ output = []
32
+ @rule.each_declaration {|dec| output << dec}
33
+ @decs.should == output
34
+ end
35
+
36
+ it "should preserve the order of declarations" do
37
+ @decs.each {|dec| @rule.add(dec) }
38
+ out = @rule.declaration_block
39
+ @decs.each_with_index do |dec, index|
40
+ dec.should == out[index]
41
+ end
42
+ end
43
+
44
+ it "should retun declaration block as an array of declarations" do
45
+ @decs.each {|dec| @rule.add(dec) }
46
+ @decs.should eql(@rule.declaration_block)
47
+ end
48
+
49
+ end
50
+
@@ -0,0 +1,14 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe StyleSheetParser do
4
+
5
+ it "should accept a file" do
6
+ ssp = StyleSheetParser.new("test/style.css")
7
+ end
8
+
9
+ it "should produce a style sheet" do
10
+ ssp = StyleSheetParser.new("test/style.css")
11
+ ss = ssp.style_sheet
12
+ ss.should be_instance_of(StyleSheet)
13
+ end
14
+ end
@@ -0,0 +1,57 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe StyleSheet do
4
+
5
+ before(:each) do
6
+ @style_sheet = StyleSheet.new
7
+ @rules = [Rule.new("Test1"), Rule.new("Test2"), Rule.new("Test3")]
8
+ @rule = Rule.new("test")
9
+ end
10
+
11
+ # is everything connected?
12
+ it "should exist" do
13
+ @style_sheet.should_not be_nil
14
+ @style_sheet.should be_an_instance_of(StyleSheet)
15
+ end
16
+
17
+ it "should be empty when created" do
18
+ @style_sheet.size.should == 0
19
+ end
20
+
21
+ it "should know how many rules it contains" do
22
+ total = 5
23
+ 1.upto(total) do |i|
24
+ @style_sheet.add(@rule)
25
+ end
26
+ @style_sheet.size.should == total
27
+ end
28
+
29
+ it "should accept rule objects" do
30
+ @style_sheet.add(@rule)
31
+ end
32
+
33
+ it "should only allow rules to be added" do
34
+ lambda { @style_sheet.add("foo") }.should raise_error(ArgumentError)
35
+ end
36
+
37
+ it "should yield all rules to a block" do
38
+ @rules.each {|rule| @style_sheet.add(rule) }
39
+ output = []
40
+ @style_sheet.each_rule {|rule| output << rule }
41
+ output.should == @rules
42
+ end
43
+
44
+ it "should return all rules as an array" do
45
+ @rules.each {|rule| @style_sheet.add(rule) }
46
+ @rules.should eql(@style_sheet.rules)
47
+ end
48
+
49
+ it "should preserve the order rules are added in" do
50
+ @rules.each {|rule| @style_sheet.add(rule) }
51
+ out = @style_sheet.rules
52
+ @rules.each_with_index do |rule, index|
53
+ rule.should == out[index]
54
+ end
55
+ end
56
+ end
57
+
@@ -0,0 +1,37 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe TemplateBuilder do
4
+
5
+ before(:each) do
6
+ @ss = StyleSheet.new
7
+ r = Rule.new("foo")
8
+ r.add(Declaration.new("margin", "0px"))
9
+ @ss.add(r)
10
+ end
11
+ it "should accept a StyleSheet" do
12
+ TemplateBuilder.new(StyleSheet.new)
13
+ end
14
+ it "should raise an argument error if it is not a stylesheet" do
15
+ lambda { TemplateBuilder.new("foo") }.should raise_error(ArgumentError)
16
+ end
17
+ it "should generate a string" do
18
+ tb = TemplateBuilder.new(@ss)
19
+ str = tb.publish
20
+ str.should be_an_instance_of(String)
21
+ end
22
+
23
+ it "should have a default template" do
24
+ TemplateBuilder::DEFAULT.should_not be_nil
25
+ TemplateBuilder::DEFAULT.should be_an_instance_of(String)
26
+ end
27
+
28
+ it "should accept a custom template to build" do
29
+ tb = TemplateBuilder.new(@ss, "A/test/file")
30
+ tb.template.should == "A/test/file"
31
+ end
32
+
33
+ it "should raise a IOError if the template file it not valid" do
34
+ lambda { tb = TemplateBuilder.new(@ss, "A/test/file"); tb.publish }.should raise_error(IOError)
35
+ end
36
+ end
37
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: csspress
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Madden
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-05-18 00:00:00 +01:00
12
+ date: 2008-05-20 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -41,6 +41,7 @@ files:
41
41
  - lib/csspress/declaration.rb
42
42
  - lib/csspress/rule.rb
43
43
  - lib/csspress/style_sheet.rb
44
+ - lib/csspress/style_sheet_parser.rb
44
45
  - lib/csspress/template_builder.rb
45
46
  - lib/csspress/version.rb
46
47
  - lib/templates/default.csst
@@ -50,8 +51,13 @@ files:
50
51
  - script/txt2html
51
52
  - setup.rb
52
53
  - spec/csspress_spec.rb
54
+ - spec/declaration_spec.rb
55
+ - spec/rule_spec.rb
53
56
  - spec/spec.opts
54
57
  - spec/spec_helper.rb
58
+ - spec/style_sheet_spec.rb
59
+ - spec/style_sheet_parser_spec.rb
60
+ - spec/template_builder_spec.rb
55
61
  - tasks/custom.rake
56
62
  - tasks/deployment.rake
57
63
  - tasks/environment.rake
@@ -65,7 +71,7 @@ has_rdoc: true
65
71
  homepage: http://csspress.rubyforge.org
66
72
  post_install_message: |+
67
73
 
68
- For more information on csspress, see http://csspress.rubyforge.org
74
+ For more information on csspress, see http://www.csspress.net
69
75
 
70
76
 
71
77
  To get cracking straight away: