csspress 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,144 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # declaration.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
+ # Declaration represents a declaration in a style sheet rule.
11
+ # It is composed of a property and a value. The property must be
12
+ # valid.
13
+ #
14
+ # Declaration takes a string and populates itself.
15
+ #
16
+ # Example:
17
+ # d = declaration.new ( "border-color : blue" )
18
+ # puts d.property #=> "border-color"
19
+ # puts d.value #=> "blue"
20
+ #
21
+ class Declaration
22
+
23
+ # Declaration property
24
+ attr_reader :property
25
+ # Declaration value
26
+ attr_reader :value
27
+
28
+ # internal error for invalid property types
29
+ #
30
+ class PropertyError < StandardError
31
+ # do nothing - just creating a specific error
32
+ end
33
+
34
+ # Properties for CSS1 to CSS3
35
+ VALID_PROPERTIES = %w(
36
+ alignment-adjust alignment-baseline appearance azimuth background background-attachment background-break
37
+ background-clip background-color background-image background-origin background-position background-repeat
38
+ background-size baseline-shift binding bookmark-label bookmark-level bookmark-target border border-bottom
39
+ border-bottom-color border-bottom-left-radius border-bottom-right-radius border-bottom-style border-bottom-width
40
+ border-break border-collapse border-color border-image border-left border-left-color border-left-style
41
+ border-left-width border-length border-radius border-right border-right-color border-right-style border-right-width
42
+ border-spacing border-style border-top border-top-color border-top-left-radius border-top-right-radius border-top-style
43
+ border-top-width border-width bottom box-align box-direction box-flex box-flex-group box-lines box-orient box-pack
44
+ box-shadow box-sizing caption-side clear clip color color-profile column-break-after column-break-before column-count
45
+ column-fill column-gap column-rule column-rule-color column-rule-style column-rule-width column-span column-width columns
46
+ content counter-increment counter-reset crop cue cue-after cue-before cursor direction display dominant-baseline
47
+ drop-initial-after-adjust drop-initial-after-align drop-initial-before-adjust drop-initial-before-align
48
+ drop-initial-size drop-initial-value elevation empty-cells fit fit-position float float-offset font
49
+ font-effect font-emphasize font-emphasize-position font-emphasize-style font-family font-size font-size-adjust
50
+ font-smooth font-stretch font-style font-variant font-weight grid-columns grid-rows hanging-punctuation height
51
+ hyphenate-after hyphenate-before hyphenate-character hyphenate-lines hyphenate-resource hyphens icon image-orientation
52
+ image-resolution inline-box-align left letter-spacing line-height line-stacking line-stacking-ruby line-stacking-shift
53
+ line-stacking-strategy list-style list-style-image list-style-position list-style-type margin margin-bottom margin-left
54
+ margin-right margin-top mark mark-after mark-before marker-offset marks marquee-direction marquee-loop marquee-speed
55
+ marquee-style max-height max-width min-height min-width move-to nav-down nav-index nav-left nav-right nav-up opacity orphans
56
+ outline outline-color outline-offset outline-style outline-width overflow overflow-style overflow-x overflow-y padding
57
+ padding-bottom padding-left padding-right padding-top page page-break-after page-break-before page-break-inside page-policy
58
+ pause pause-after pause-before phonemes pitch pitch-range play-during position presentation-level punctuation-trim quotes
59
+ rendering-intent resize rest rest-after rest-before richness right rotation rotation-point ruby-align ruby-overhang ruby-position
60
+ ruby-span size speak speak-header speak-numeral speak-punctuation speech-rate stress string-set tab-side table-layout target
61
+ target-name target-new target-position text-align text-align-last text-decoration text-emphasis text-height text-indent
62
+ text-justify text-outline text-replace text-shadow text-transform text-wrap top unicode-bidi vertical-align visibility
63
+ voice-balance voice-duration voice-family voice-pitch voice-pitch-range voice-rate voice-stress voice-volume volume
64
+ white-space white-space-collapse widows width word-break word-spacing word-wrap z-index
65
+ )
66
+
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
74
+ end
75
+
76
+ # Print out the rule neatly
77
+ #
78
+ def to_s
79
+ "#{@property}:#{@value}"
80
+ end
81
+
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
+ end
@@ -0,0 +1,123 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # rule.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
+ # Rule represents a rule in a style sheet.
11
+ # An example of a rule would be:
12
+ # body { margin : 0; padding : 0 }
13
+ #
14
+ # The components of a rule are:
15
+ # name { declarations }
16
+ #
17
+ # All declarations of Rule can be accessed using the
18
+ # .each_declaration(){} method where each declaration
19
+ # is passed to the block as a Declaration object.
20
+ #
21
+ # Example:
22
+ # r = Rule.new ( "foo { margin: 0; padding: 0 }" )
23
+ # r.each_declaration do |dec|
24
+ # puts dec
25
+ # end
26
+ # puts r.name
27
+ #
28
+ class Rule
29
+
30
+ # name of the Rule
31
+ attr_reader :name
32
+ # declarations contained within Rule
33
+ attr_reader :declarations
34
+
35
+ # Create a new Rule from a string
36
+ # (The string should be a valid CSS rule!)
37
+ #
38
+ def initialize( string )
39
+ rp = RuleParser.new( string )
40
+ @name = rp.name
41
+ @declarations = rp.declarations
42
+ end
43
+
44
+ # Yeild all declarations for self
45
+ #
46
+ def each_declaration
47
+ @declarations.each do |declaration|
48
+ yield declaration
49
+ end
50
+ end
51
+
52
+ # Print out the rule neatly
53
+ #
54
+ def to_s
55
+ "#{@name}{#{@declarations.join(";")}}"
56
+ end
57
+
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
116
+ 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
123
+ end
@@ -0,0 +1,243 @@
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
+ # StyleSheet is a container class for Rule objects which can be added
11
+ # individually using the .add() method. The Rule objects that StyleSheet
12
+ # contains can be accessed using the .each_rule(){} method which yields
13
+ # each Rule to the block.
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
+ # Example:
21
+ # ss = StyleSheet.new ( "foo.css" )
22
+ # tb = TemplateBuilder.new ( ss )
23
+ # puts tb.publish # output compressed version of ss
24
+ #
25
+ class StyleSheet
26
+
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)
38
+ @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
+ end
49
+
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
+ #
69
+ def add(rule)
70
+ @rules << Rule.new(rule)
71
+ self
72
+ end
73
+
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
+ #
86
+ def size
87
+ @rules.size
88
+ end
89
+
90
+ # Alias of size
91
+ #
92
+ def length
93
+ size
94
+ end
95
+
96
+ private
97
+
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
216
+ 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
242
+ end
243
+ end