style_train 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+