style_train 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/spec/spec.opts ADDED
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --format specdoc
3
+ --loadby mtime
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+
7
+ require 'style_train'
8
+
9
+ RSpec.configure do |config|
10
+ end
11
+
@@ -0,0 +1,74 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{style_train}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Kane Baccigalupi"]
12
+ s.date = %q{2011-02-17}
13
+ s.description = %q{style_train builds CSS using pure Ruby, not a DSL interpreted via Ruby. This allows inheritance, modules, instance level calculations and all the goodness Ruby can offer.}
14
+ s.email = %q{baccigalupi@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ "LISENCE",
20
+ "README.rdoc",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "lib/style_train.rb",
24
+ "lib/style_train/color.rb",
25
+ "lib/style_train/color_types/color_type.rb",
26
+ "lib/style_train/color_types/hex_color.rb",
27
+ "lib/style_train/color_types/hsl_color.rb",
28
+ "lib/style_train/color_types/keyword_color.rb",
29
+ "lib/style_train/color_types/rgb_color.rb",
30
+ "lib/style_train/sheet.rb",
31
+ "lib/style_train/support/gnash.rb",
32
+ "lib/style_train/support/numbers.rb",
33
+ "lib/style_train/support/string.rb",
34
+ "spec/color/color_spec.rb",
35
+ "spec/color/color_type_spec.rb",
36
+ "spec/color/hex_color_spec.rb",
37
+ "spec/color/keyword_color_spec.rb",
38
+ "spec/color/rgb_color_spec.rb",
39
+ "spec/numbers_spec.rb",
40
+ "spec/sheet_spec.rb",
41
+ "spec/spec.opts",
42
+ "spec/spec_helper.rb",
43
+ "style_train.gemspec",
44
+ "utils/alexch_color_gist/color.rb",
45
+ "utils/alexch_color_gist/color_test.rb",
46
+ "utils/overview.txt",
47
+ "utils/stylesheet.txt"
48
+ ]
49
+ s.homepage = %q{http://github.com/baccigalupi/style_train}
50
+ s.require_paths = ["lib"]
51
+ s.rubygems_version = %q{1.3.7}
52
+ s.summary = %q{style_train builds CSS with Ruby}
53
+ s.test_files = [
54
+ "spec/color/color_spec.rb",
55
+ "spec/color/color_type_spec.rb",
56
+ "spec/color/hex_color_spec.rb",
57
+ "spec/color/keyword_color_spec.rb",
58
+ "spec/color/rgb_color_spec.rb",
59
+ "spec/numbers_spec.rb",
60
+ "spec/sheet_spec.rb",
61
+ "spec/spec_helper.rb"
62
+ ]
63
+
64
+ if s.respond_to? :specification_version then
65
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
66
+ s.specification_version = 3
67
+
68
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
69
+ else
70
+ end
71
+ else
72
+ end
73
+ end
74
+
@@ -0,0 +1,160 @@
1
+ # == Schema Information
2
+ # Schema version: 10
3
+ #
4
+ # Table name: descriptions
5
+ #
6
+ # id :integer(4) not null, primary key
7
+ # type :string(255) not null
8
+ # person_id :integer(4) not null
9
+ # mood_id :integer(4) not null
10
+ # value :integer(4) not null
11
+ # use_consensus :boolean(1) not null
12
+ # created_at :datetime
13
+ # updated_at :datetime
14
+ #
15
+
16
+ # the value is an integer in RGB space
17
+ class Color < Description
18
+
19
+ NEUTRAL = "#888888"
20
+
21
+ def self.to_rgb(val)
22
+ val.nil? ? NEUTRAL : "#%.6x" % val
23
+ end
24
+
25
+ def self.consensus(mood)
26
+ all = mood.colors
27
+ if all.empty?
28
+ return nil
29
+ else
30
+ # all = Color.find(:all, :conditions => {:mood_id => mood.id})
31
+ hue_sum = saturation_sum = lightness_sum = 0
32
+ all.each_with_index do |color,i|
33
+ hue_sum += color.hue
34
+ saturation_sum += color.saturation
35
+ lightness_sum += color.lightness
36
+ end
37
+ n = all.size
38
+ from_hsl [hue_sum/n,saturation_sum/n,lightness_sum/n]
39
+ end
40
+ end
41
+
42
+ def self.from_hsl(hsl_array)
43
+ rgb_array = hsl_to_rgb(hsl_array)
44
+ new(:value =>
45
+ (rgb_array[0] * 0xFF).round * 0x010000 +
46
+ (rgb_array[1] * 0xFF).round * 0x000100 +
47
+ (rgb_array[2] * 0xFF).round
48
+ )
49
+ end
50
+
51
+ def initialize(options = {})
52
+ super(options)
53
+ self.rgb = options[:rgb] if options[:rgb]
54
+ end
55
+
56
+ def min
57
+ 0
58
+ end
59
+
60
+ def max
61
+ 0xffffff
62
+ end
63
+
64
+ def rgb=(s)
65
+ self.value = s.gsub(/^\#/, "0x").to_i(16)
66
+ end
67
+
68
+ def rgb
69
+ Color.to_rgb(value)
70
+ end
71
+
72
+ def red
73
+ (value / 0x10000) & 0xff
74
+ end
75
+
76
+ def green
77
+ (value / 0x100) & 0xff
78
+ end
79
+
80
+ def blue
81
+ (value) & 0xff
82
+ end
83
+
84
+ def hue
85
+ hsl[0]
86
+ end
87
+
88
+ def saturation
89
+ hsl[1]
90
+ end
91
+
92
+ def lightness
93
+ hsl[2]
94
+ end
95
+
96
+ def contrast
97
+ lightness < 0.5 ? "#ffffff" : '#000000'
98
+ end
99
+
100
+ # Various color utility functions stolen from Farbtastic and converted from JavaScript
101
+ # Farbtastic was written by Steven Wittens and is licensed under the GPL.
102
+
103
+ def hsl
104
+ r = red/255.0
105
+ g = green/255.0
106
+ b = blue/255.0
107
+ min = [r,g,b].min
108
+ max = [r,g,b].max
109
+ delta = max - min;
110
+ l = (min + max) / 2;
111
+ s = 0;
112
+ if (l > 0 && l < 1)
113
+ s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l));
114
+ end
115
+ h = 0;
116
+ if (delta > 0)
117
+ if (max == r && max != g)
118
+ h += (g - b) / delta;
119
+ end
120
+ if (max == g && max != b)
121
+ h += (2 + (b - r) / delta);
122
+ end
123
+ if (max == b && max != r)
124
+ h += (4 + (r - g) / delta);
125
+ end
126
+ h /= 6;
127
+ end
128
+ [h, s, l];
129
+ end
130
+
131
+ def self.hsl_to_rgb(hsl)
132
+ h = hsl[0]
133
+ s = hsl[1]
134
+ l = hsl[2]
135
+ m2 = (l <= 0.5) ? l * (s + 1) : l + s - l*s;
136
+ m1 = l * 2 - m2;
137
+ return [
138
+ hue_to_rgb(m1, m2, h+0.33333),
139
+ hue_to_rgb(m1, m2, h),
140
+ hue_to_rgb(m1, m2, h-0.33333)
141
+ ]
142
+ end
143
+
144
+ def self.hue_to_rgb(m1, m2, h)
145
+ h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h);
146
+ if (h * 6 < 1)
147
+ return m1 + (m2 - m1) * h * 6;
148
+ end
149
+ if (h * 2 < 1)
150
+ return m2;
151
+ end
152
+ if (h * 3 < 2)
153
+ return m1 + (m2 - m1) * (0.66666 - h) * 6;
154
+ end
155
+ return m1;
156
+ end
157
+
158
+ NONE = Color.new(:rgb => NEUTRAL)
159
+
160
+ end
@@ -0,0 +1,176 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class ColorTest < MoodlogTestCase
4
+ fixtures :people, :moods
5
+
6
+ def setup
7
+ @palette = [
8
+ @white = Color.new(:value => 0xffffff),
9
+ @black = Color.new(:value => 0x000000),
10
+ @red = Color.new(:value => 0xff0000),
11
+ @green = Color.new(:value => 0x00ff00),
12
+ @blue = Color.new(:value => 0x0000ff),
13
+ @fuchsia = Color.new(:value => 0xff00ff),
14
+ @purple = Color.new(:value => 0x800080),
15
+ @turquoise = Color.new(:value => 0x48D1CC),
16
+ Color.new(:value => 0x112233),
17
+ Color.new(:value => 0x001100),
18
+ Color.new(:value => 0x000011),
19
+ Color.new(:value => 0x000001),
20
+ ]
21
+ end
22
+
23
+ def test_new_with_rgb
24
+ color = Color.new(:rgb => "#ffffff")
25
+ assert_equal 0xffffff, color.value
26
+ end
27
+
28
+ def test_create_with_rgb
29
+ color = create_color(:rgb => "#ffffff")
30
+ assert_equal 0xffffff, color.value
31
+ end
32
+
33
+ def test_create_with_rgb_case_insensitive
34
+ color = create_color(:rgb => "#fFFfFF")
35
+ assert_equal 0xffffff, color.value
36
+ end
37
+
38
+ def test_update_with_rgb
39
+ color = create_color(:rgb => "#ffffff")
40
+ color.update_attributes(:rgb => "#000011")
41
+ assert_equal 0x000011, color.value
42
+ end
43
+
44
+ def test_get_rgb
45
+ ["#ffffff", "#112233", "#001100", "#000011", "#000001", "#000000"].each do |s|
46
+ color = create_color(:rgb => s)
47
+ assert_equal s, color.rgb
48
+ end
49
+ end
50
+
51
+ def test_to_rgb
52
+ assert_equal "#dababe", Color.to_rgb(0xdababe)
53
+ assert_equal Color::NEUTRAL, Color.to_rgb(nil)
54
+ end
55
+
56
+ def test_hsl_for_black
57
+ black = create_color(:rgb => "#000000")
58
+ assert_equal 0, black.hue
59
+ assert_equal 0, black.saturation
60
+ assert_equal 0, black.lightness
61
+ end
62
+
63
+ def test_hsl_for_white
64
+ white = create_color(:rgb => "#FFFFFF")
65
+ assert_equal 0, white.hue
66
+ assert_equal 0, white.saturation
67
+ assert_equal 1, white.lightness
68
+ end
69
+
70
+ def test_hsl_to_rgb
71
+ random_colors.each do |color|
72
+ # assert_between_0_and_1 color.hue # todo: figure out why this is possible
73
+ assert_between_0_and_1 color.saturation
74
+ assert_between_0_and_1 color.lightness
75
+ assert_equal color.rgb, Color.from_hsl(color.hsl).rgb
76
+ end
77
+ end
78
+
79
+ def assert_between_0_and_1(x)
80
+ assert x >= 0, "#{x} should be >= 0"
81
+ assert x <= 1.0 || approx_equal?(x, 1.0), "#{x} should be <= 1.0"
82
+ end
83
+
84
+ def approx_equal?(a,b,threshold = 0.0000001)
85
+ (a-b).abs<threshold
86
+ end
87
+
88
+
89
+ def random_colors
90
+ rgbs = @palette
91
+ 50.times { rgbs << Color.new(:rgb => "#%.6x" % rand(0x1000000).to_i) }
92
+ rgbs
93
+ end
94
+
95
+ def test_contrast
96
+ assert_equal "#ffffff", create_color(:rgb => "#000000").contrast
97
+ assert_equal "#000000", create_color(:rgb => "#ffffff").contrast
98
+
99
+ assert_equal "#000000", create_color(:rgb => "#888888").contrast
100
+ assert_equal "#ffffff", create_color(:rgb => "#777777").contrast
101
+
102
+ random_colors.each do |color|
103
+ assert_equal color.lightness < 0.5 ? '#ffffff' : '#000000', color.contrast, color.rgb
104
+ end
105
+ end
106
+
107
+ def test_consensus_where_none
108
+ assert_nil Color.consensus(moods(:happy))
109
+ end
110
+
111
+ def test_consensus_where_one
112
+ create_color(:person => people(:quentin), :mood => moods(:happy), :rgb => "#FF0000")
113
+ assert_equal "#ff0000", Color.consensus(moods(:happy)).rgb
114
+ end
115
+
116
+ def test_parts
117
+ assert_equal 0xff, @red.red
118
+ assert_equal 0, @green.red
119
+ assert_equal 0, @blue.red
120
+ assert_equal 0xff, @fuchsia.red
121
+
122
+ assert_equal 0x00, @red.green
123
+ assert_equal 0xff, @green.green
124
+ assert_equal 0x00, @blue.green
125
+ assert_equal 0x00, @fuchsia.green
126
+ end
127
+
128
+ # todo: use HSL instead of RGB to find average
129
+ # def test_consensus_where_many
130
+ # mood = moods(:happy)
131
+ # red_sum = green_sum = blue_sum = 0
132
+ # @palette.each_with_index do |x,i|
133
+ # person = Person.create!(:username => "person#{i}",
134
+ # :password => 'test', :password_confirmation => 'test',
135
+ # :addresses => {0 => {:email => "person#{i}@example.com"}})
136
+ # color = create_color(:person => person, :mood => mood, :rgb => x.rgb)
137
+ # red_sum += color.red
138
+ # green_sum += color.green
139
+ # blue_sum += color.blue
140
+ # end
141
+ # consensus = Color.consensus(mood)
142
+ # n = @palette.size
143
+ # assert_equal red_sum/n, consensus.red
144
+ # assert_equal blue_sum/n, consensus.blue
145
+ # assert_equal green_sum/n, consensus.green
146
+ # end
147
+ #
148
+ def test_consensus_where_many
149
+ mood = moods(:happy)
150
+ hue_sum = saturation_sum = lightness_sum = 0
151
+ @palette.each_with_index do |x,i|
152
+ person = Person.create!(:username => "person#{i}",
153
+ :password => 'test', :password_confirmation => 'test',
154
+ :addresses => {0 => {:email => "person#{i}@example.com"}})
155
+ color = create_color(:person => person, :mood => mood, :rgb => x.rgb)
156
+ hue_sum += color.hue
157
+ saturation_sum += color.saturation
158
+ lightness_sum += color.lightness
159
+ end
160
+ consensus = Color.consensus(mood)
161
+ n = @palette.size
162
+ assert_nearly_equal hue_sum/n, consensus.hue
163
+ assert_nearly_equal lightness_sum/n, consensus.lightness
164
+ assert_nearly_equal saturation_sum/n, consensus.saturation
165
+ end
166
+
167
+ def assert_nearly_equal(expected, actual)
168
+ assert_equal((expected*10.0).round, (actual*10.0).round, "Expected #{expected} and #{actual} to be nearly equal")
169
+ end
170
+
171
+ def create_color(options = {})
172
+ options = {:person => people(:quentin), :mood => moods(:happy)}.merge(options)
173
+ Color.create(options)
174
+ end
175
+
176
+ end
@@ -0,0 +1,151 @@
1
+ StyleTrain - Ruby CSS generator
2
+ Similar Packages:
3
+ Sass - DSL easy nesting, variables
4
+ Less - more Rubyish than Sass, but still a DSL. nesting, variables
5
+
6
+ Goals:
7
+ Shared with other packages:
8
+ Reduce repetition so updates can happen in just one place
9
+ As such Keep colors and dimensions around as constants
10
+ Allow calculations with colors and dimensions
11
+ Unique and hopefully of value:
12
+ Be real Ruby instead of a parsed DSL
13
+ Allow Ruby inheritance, inclusion
14
+ Usable inline with Erector, etc
15
+
16
+ Ideas on the domain:
17
+ style should allow inheritance
18
+ style allows non-inheritance mix in
19
+ style output to a string
20
+
21
+ have set/collection object that aggregates a set of styles to a file or string
22
+ set/collection should allow inclusion of strings defining custom styles (browser workarounds)
23
+ should generate a reset.css Reset < StyleTrain::Set, includes the typical reset stuff
24
+
25
+ colors are saved in a pallete object
26
+ color can be added, subtracted, averaged with another color.
27
+ color converts between color types # rgb() vs hex
28
+
29
+ variables: color, size; should be constants that can be used in calculations
30
+
31
+ a style should be able to calculate its full width and height, where applicable
32
+ a style can have a full_width, which will calculate width from borders &| margins &| padding
33
+ style full_width should work for max and min width too
34
+ style should be able to base its full_width on another style
35
+
36
+
37
+ USAGES:
38
+ ----------------------------------------------------
39
+ General Usage:
40
+
41
+ class Border < StyleTrain::Style
42
+ # ...
43
+ end
44
+
45
+ Border.to_s
46
+
47
+ class ModifiedBorder < Border
48
+ # modifications
49
+ end
50
+
51
+ ModifiedBorder.to_s
52
+
53
+ class BoxWithBorder < StyleTrain::Style
54
+ selector '.box.border'
55
+ include Border # or mixin Border
56
+ end
57
+
58
+ BoxWithBorder.to_s
59
+ # .box.border {
60
+ # border: 1px solid black;
61
+ # /* ... the rest of the box and border styles */
62
+ # }
63
+
64
+
65
+ _______________________________________________________
66
+ Set Usage
67
+
68
+ css = StyleTrain::Set.new( BoxWithBorder, ... list of other styles )
69
+ css.to_s
70
+ # .box.border {
71
+ # border: 1px solid black;
72
+ # /* ... the rest of the box and border styles */
73
+ # }
74
+ # /* plus any other styles passed in to the initializer */
75
+ css.add( '.panel .box.border', my_stlye ) # my_stlye can also be a Style class
76
+ css.to_s # all the styles
77
+ css.to_file # saves file (master.css) to location (if specified) or returns tempfile
78
+
79
+
80
+ ------------------------------------------------------
81
+ Style Generation Usage:
82
+
83
+ class Border < StyleTrain::Style
84
+ border
85
+ end
86
+
87
+ Border.to_s
88
+ # { border: 1px solid black; }
89
+
90
+ class Border < StyleTrain::Style
91
+ border :color => :white
92
+ end
93
+
94
+ Border.to_s
95
+ # { border: 1px solid white; }
96
+
97
+ class Border < StyleTrain::Style
98
+ border :color => 'cdcdcd' # or :color => '#cdcdcd', or :color => 'rgb(...)'
99
+ end
100
+
101
+ Border.to_s
102
+ # { border: 1px solid #cdcdcd; }
103
+
104
+ ---------------------------------------------------------
105
+ Palettes and Colors
106
+
107
+ class Colors < StyleTrain::Palette
108
+ color :main_background => :ededed, :red => rgb(1,0,0) # etc
109
+ end
110
+
111
+ Colors[:main_background] + 'eee'
112
+ Colors[:main_background].class # StyleTrain::Color
113
+
114
+ ----------------------------------------------------------
115
+ Including Classes ... what? Here is the concept in play
116
+ class Classy
117
+ def self.talk
118
+ 'I am a class'
119
+ end
120
+ end
121
+
122
+ module Moduley
123
+ def self.talk
124
+ 'I am a module'
125
+ end
126
+ end
127
+
128
+ class FlexibleClass
129
+ def self.include( thing )
130
+ if thing.class == Class
131
+ puts thing.talk + ' and am being included'
132
+ else
133
+ super
134
+ end
135
+ end
136
+ end
137
+
138
+ class MyFlexibleClass < FlexibleClass
139
+ include Classy
140
+ end
141
+
142
+ # this will puts out 'I am a class and am being included', it won't currently add any methods though
143
+
144
+
145
+
146
+
147
+
148
+
149
+
150
+
151
+