style_train 0.2.1 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.1
1
+ 0.2.3
@@ -82,7 +82,19 @@ module StyleTrain
82
82
 
83
83
  self.background_set = true
84
84
  @background
85
- end
85
+ end
86
+
87
+ def step(end_color, steps=10)
88
+ start_color = self.delegate
89
+ end_color = end_color.delegate
90
+ array = [start_color]
91
+ (2..(steps-1)).each do |number|
92
+ ratio = 1 - (steps-number)/steps.to_f
93
+ array << start_color.mix(end_color, ratio)
94
+ end
95
+ array << end_color
96
+ array
97
+ end
86
98
 
87
99
  def render(render_style=nil)
88
100
  if render_style && render_style.to_sym == :ie
@@ -87,12 +87,13 @@ module StyleTrain
87
87
  end
88
88
 
89
89
  # blending
90
- def mix( color )
90
+ def mix( color, mix_ratio=0.5 )
91
+ mix_ratio = 1-mix_ratio
91
92
  mixed = self.dup
92
- mixed.r = self.class.average(self.r, color.r)
93
- mixed.g = self.class.average(self.g, color.g)
94
- mixed.b = self.class.average(self.b, color.b)
95
- mixed.alpha = self.class.average(self.alpha, color.alpha, false)
93
+ mixed.r = ratio(self.r, color.r, mix_ratio)
94
+ mixed.g = ratio(self.g, color.g, mix_ratio)
95
+ mixed.b = ratio(self.b, color.b, mix_ratio)
96
+ mixed.alpha = ratio(self.alpha, color.alpha, mix_ratio, false)
96
97
  mixed.build
97
98
  mixed
98
99
  end
@@ -109,13 +110,27 @@ module StyleTrain
109
110
  end
110
111
 
111
112
  def self.blend(first, second, ratio)
112
- blended = (first*ratio + second*(1-ratio)).round
113
+ ratio(first, second, ratio)
113
114
  end
114
115
 
115
116
  def self.average(first, second, round=true)
116
- averaged = ((first + second)/2.0)
117
- round ? averaged.round : averaged
117
+ ratio(first, second, round)
118
+ end
119
+
120
+ def self.ratio(first, second, first_ratio=0.5, round=true)
121
+ second_ratio = 1-first_ratio
122
+ value = first*first_ratio + second*second_ratio
123
+ round ? value.round : value
124
+ end
125
+
126
+ def ratio *args
127
+ self.class.ratio *args
128
+ end
129
+
130
+ def average *args
131
+ self.class.average *args
118
132
  end
133
+
119
134
 
120
135
  def self.blend_alphas(first, second)
121
136
  base, blender = first > second ? [first, second] : [second, first]
@@ -61,7 +61,9 @@ module StyleTrain
61
61
 
62
62
  def property( label, value )
63
63
  value = value.join(' ') if value.is_a?(Array)
64
- self.output << "\n#{indent}#{label}: #{value};"
64
+ str = "\n#{indent}#{label}: #{value};"
65
+ self.output << str
66
+ str
65
67
  end
66
68
 
67
69
  def background( opts )
@@ -222,6 +224,107 @@ module StyleTrain
222
224
  RUBY
223
225
  end
224
226
 
227
+ def corners(opts)
228
+ str = ""
229
+ if opts.is_a?(Hash)
230
+ if opts[:left]
231
+ str << corner_top_left( opts[:left] )
232
+ str << corner_bottom_left( opts[:left] )
233
+ end
234
+
235
+ if opts[:right]
236
+ str << corner_top_right( opts[:right] )
237
+ str << corner_bottom_right( opts[:right] )
238
+ end
239
+
240
+ if opts[:top]
241
+ str << corner_top_right( opts[:top] )
242
+ str << corner_top_left( opts[:top] )
243
+ end
244
+
245
+ if opts[:bottom]
246
+ str << corner_bottom_right( opts[:bottom] )
247
+ str << corner_bottom_left( opts[:bottom] )
248
+ end
249
+
250
+ str << corner_top_left( opts[:top_left] ) if opts[:top_left]
251
+ str << corner_top_right( opts[:top_right] ) if opts[:top_right]
252
+ str << corner_bottom_left( opts[:bottom_left] ) if opts[:bottom_left]
253
+ str << corner_bottom_right( opts[:bottom_right] ) if opts[:bottom_right]
254
+ else
255
+ str << property('border-radius', opts )
256
+ str << property('-moz-border-radius', opts)
257
+ str << property('-webkit-border-radius', opts)
258
+ end
259
+ str
260
+ end
261
+
262
+ def corner_top_left size
263
+ str = ""
264
+ str << property('border-top-left-radius', size)
265
+ str << property('-moz-border-radius-topleft', size)
266
+ str << property('-webkit-border-top-left-radius', size)
267
+ str
268
+ end
269
+
270
+ def corner_bottom_left size
271
+ str = ""
272
+ str << property('border-bottom-left-radius', size)
273
+ str << property('-moz-border-radius-bottomleft', size)
274
+ str << property('-webkit-border-bottom-left-radius', size)
275
+ str
276
+ end
277
+
278
+ def corner_top_right size
279
+ str = ""
280
+ str << property('border-top-right-radius', size)
281
+ str << property('-moz-border-radius-topright', size)
282
+ str << property('-webkit-border-top-right-radius', size)
283
+ str
284
+ end
285
+
286
+ def corner_bottom_right size
287
+ str = ""
288
+ str << property('border-bottom-right-radius', size)
289
+ str << property('-moz-border-radius-bottomright', size)
290
+ str << property('-webkit-border-bottom-right-radius', size)
291
+ str
292
+ end
293
+
294
+ def shadow(opts={})
295
+ opts[:horizontal_offset] ||= default_shadow_offset
296
+ opts[:vertical_offset] ||= default_shadow_offset
297
+ opts[:blur] ||= default_shadow_offset
298
+ opts[:color] ||= default_shadow_color
299
+ str = ""
300
+ str << property('box-shadow', shadow_options(opts))
301
+ str << property('-webkit-box-shadow', shadow_options(opts))
302
+ str << property('-moz-box-shadow', shadow_options(opts))
303
+ str
304
+ end
305
+
306
+ def default_shadow_offset
307
+ 0.25.em # this can be overwritten on a class by class basis
308
+ end
309
+
310
+ def default_shadow_color
311
+ :black # this too
312
+ end
313
+
314
+ def shadow_options(opts)
315
+ "#{opts[:inner] ? 'inset ' : ''}#{opts[:horizontal_offset]} #{opts[:vertical_offset]} #{opts[:blur]} #{opts[:color]}"
316
+ end
317
+
318
+ def gradient(opts={})
319
+ raise ArgumentError, "gradient styles require a :start and :end color" unless opts[:start] && opts[:end]
320
+ opts[:from] ||= 'top'
321
+ direction = opts[:from] == 'top' ? "left top, left bottom" : "left top, right top"
322
+ str = ""
323
+ str << property('background', opts[:end])
324
+ str << property('background', "-webkit-gradient(linear, #{direction}, from(#{opts[:start]}), to(#{opts[:end]}))")
325
+ str << property('background', "-moz-linear-gradient(#{opts[:from]}, #{opts[:start]}, #{opts[:end]})")
326
+ str
327
+ end
225
328
 
226
329
  def content
227
330
  # override me in subclasses
@@ -1,6 +1,6 @@
1
1
  module StyleTrain
2
2
  class Theme
3
- attr_accessor :value_hash, :name
3
+ attr_accessor :value_hash, :name, :palette
4
4
 
5
5
  def self.required_keys *args
6
6
  if args.empty?
@@ -14,6 +14,14 @@ module StyleTrain
14
14
  @themes ||= Gnash.new
15
15
  end
16
16
 
17
+ def self.defaults hash=nil
18
+ if hash
19
+ @defaults = Gnash.new(hash)
20
+ else
21
+ @defaults || Gnash.new
22
+ end
23
+ end
24
+
17
25
  def self.[](key)
18
26
  themes[key]
19
27
  end
@@ -22,15 +30,23 @@ module StyleTrain
22
30
  themes.keys.map{|k| k.to_sym}
23
31
  end
24
32
 
25
- def initialize(name, value_hash)
33
+ def initialize(name, value_hash, palette = {})
26
34
  raise ArgumentError, "Unique name is required as first argument" if !name || self.class.themes[name]
27
- missing_keys = self.class.required_keys - value_hash.keys
35
+ self.palette = palette
36
+ self.value_hash = Gnash.new(self.class.defaults.merge(substitute(value_hash)))
37
+ missing_keys = self.class.required_keys - self.value_hash.keys.map{|k| k.to_sym}
28
38
  raise ArgumentError, "Required keys not provided: #{missing_keys.map{|k| k.inspect}.join(", ")}" if !missing_keys.empty?
29
- self.value_hash = Gnash.new(value_hash)
30
39
  self.name = name
31
40
  self.class.themes[name] = self
32
41
  end
33
42
 
43
+ def substitute hash
44
+ hash.each do |key, value|
45
+ hash[key] = palette[value] if palette[value]
46
+ end
47
+ hash
48
+ end
49
+
34
50
  def [](key)
35
51
  value_hash[key]
36
52
  end
@@ -221,4 +221,32 @@ describe Color do
221
221
  Color.new(:black, :alpha => 0.5).to_s.should == Color.new(:black, :alpha => 0.5).render
222
222
  end
223
223
  end
224
+
225
+ describe 'stepping' do
226
+ before :all do
227
+ @black = Color.new('#000')
228
+ @yellow = Color.new(:lightyellow, :alpha => 0.5)
229
+ @steps = @black.step(@yellow)
230
+ end
231
+
232
+ it 'returs an array' do
233
+ @steps.is_a?(Array).should be_true
234
+ end
235
+
236
+ it 'has 10 steps by default' do
237
+ @steps.size.should == 10
238
+ end
239
+
240
+ it 'has takes optional number of steps' do
241
+ @black.step(@yellow, 5).size.should == 5
242
+ end
243
+
244
+ it 'first color should be the starting point' do
245
+ @steps.first.should == @black.delegate
246
+ end
247
+
248
+ it 'last color should be the last point' do
249
+ @steps.last.should == @yellow.delegate
250
+ end
251
+ end
224
252
  end
@@ -271,7 +271,7 @@ describe ColorType do
271
271
  @hex = HexColor.new(:color => '#666')
272
272
  end
273
273
 
274
- describe 'averaging' do
274
+ describe 'averaging (getting a midway point)' do
275
275
  it 'should average the r, g, and b values' do
276
276
  color = @rgb.mix(@hex)
277
277
  color.r.should == ((102+20)/2.0).round
@@ -358,8 +358,27 @@ describe ColorType do
358
358
  end
359
359
  end
360
360
 
361
- describe 'stepping'
362
-
361
+ describe 'blending a ratio of one color to the other' do
362
+ it 'should mix in the correct percentage r, g, and b values' do
363
+ color = @rgb.mix(@hex, 0.25) # only 25% of the @hex
364
+ color.r.should == (102*0.25 + 20*0.75).round
365
+ color.g.should == (102*0.25 + 40*0.75).round
366
+ color.b.should == (102*0.25 + 60*0.75).round
367
+ end
368
+
369
+ it 'should average the alpha' do
370
+ color = @rgb.mix(@hex, 0.25)
371
+ color.alpha.should == 0.5*0.75 + 1*0.25
372
+ end
373
+
374
+ it 'should return the original color type' do
375
+ color = @rgb.mix(@hex, 0.25)
376
+ color.class.should == RGBcolor
377
+
378
+ color = @hex.mix(@rgb, 0.25)
379
+ color.class.should == HexColor
380
+ end
381
+ end
363
382
  end
364
383
 
365
384
  describe 'rendering' do
data/spec/sheet_spec.rb CHANGED
@@ -514,6 +514,180 @@ describe Sheet do
514
514
  end
515
515
  end
516
516
  end
517
+
518
+ describe 'css 3 goodies' do
519
+ before :all do
520
+ @sheet = Sheet.new
521
+ end
522
+
523
+ describe '#corners' do
524
+ it 'makes all corners the specified roundness' do
525
+ str = @sheet.corners(32.px)
526
+ str.should include "border-radius: 32px"
527
+ str.should include "-moz-border-radius: 32px"
528
+ str.should include "-webkit-border-radius: 32px"
529
+ end
530
+
531
+ it '#corner_top_left make the correct three declarations' do
532
+ str = @sheet.corner_top_left(1.em)
533
+ str.should include(
534
+ "border-top-left-radius: 1em",
535
+ "-moz-border-radius-topleft: 1em",
536
+ "-webkit-border-top-left-radius: 1em"
537
+ )
538
+ end
539
+
540
+ it '#corners makes a top left corner' do
541
+ @sheet.corners(:top_left => 2.em).should == @sheet.corner_top_left(2.em)
542
+ end
543
+
544
+ it '#corner_top_right make the correct three declarations' do
545
+ str = @sheet.corner_top_right(1.5.em)
546
+ str.should include(
547
+ "border-top-right-radius: 1.5em",
548
+ "-moz-border-radius-topright: 1.5em",
549
+ "-webkit-border-top-right-radius: 1.5em"
550
+ )
551
+ end
552
+
553
+ it '#corners makes a top left corner' do
554
+ @sheet.corners(:top_right => 1.em).should == @sheet.corner_top_right(1.em)
555
+ end
556
+
557
+
558
+ it '#corner_bottom_right make the correct three declarations' do
559
+ str = @sheet.corner_bottom_right(1.5.em)
560
+ str.should include(
561
+ "border-bottom-right-radius: 1.5em",
562
+ "-moz-border-radius-bottomright: 1.5em",
563
+ "-webkit-border-bottom-right-radius: 1.5em"
564
+ )
565
+ end
566
+
567
+ it '#corners makes a top right corner' do
568
+ @sheet.corners(:bottom_right => 1.em).should == @sheet.corner_bottom_right(1.em)
569
+ end
570
+
571
+ it '#corner_bottom_left make the correct three declarations' do
572
+ str = @sheet.corner_bottom_left(1.5.em)
573
+ str.should include(
574
+ "border-bottom-left-radius: 1.5em",
575
+ "-moz-border-radius-bottomleft: 1.5em",
576
+ "-webkit-border-bottom-left-radius: 1.5em"
577
+ )
578
+ end
579
+
580
+ it '#corners makes a top left corner' do
581
+ @sheet.corners(:bottom_left => 1.em).should == @sheet.corner_bottom_left(1.em)
582
+ end
583
+
584
+ it 'makes both top corners at once' do
585
+ str = @sheet.corners(:top => 20.px)
586
+ str.should include "border-top-left-radius: 20px"
587
+ str.should include "-moz-border-radius-topleft: 20px"
588
+ str.should include "-webkit-border-top-left-radius: 20px"
589
+ str.should include "border-top-right-radius: 20px"
590
+ str.should include "-moz-border-radius-topright: 20px"
591
+ str.should include "-webkit-border-top-right-radius: 20px"
592
+ end
593
+
594
+ it 'makes both bottom corners at once' do
595
+ str = @sheet.corners(:bottom => 30.px)
596
+ str.should include "border-bottom-left-radius: 30px"
597
+ str.should include "-moz-border-radius-bottomleft: 30px"
598
+ str.should include "-webkit-border-bottom-left-radius: 30px"
599
+ str.should include "border-bottom-right-radius: 30px"
600
+ str.should include "-moz-border-radius-bottomright: 30px"
601
+ str.should include "-webkit-border-bottom-right-radius: 30px"
602
+ end
603
+
604
+ it 'makes both left corners at once' do
605
+ str = @sheet.corners(:left => 10.px)
606
+ str.should include "border-bottom-left-radius: 10px"
607
+ str.should include "-moz-border-radius-bottomleft: 10px"
608
+ str.should include "-webkit-border-bottom-left-radius: 10px"
609
+ str.should include "border-top-left-radius: 10px"
610
+ str.should include "-moz-border-radius-topleft: 10px"
611
+ str.should include "-webkit-border-top-left-radius: 10px"
612
+
613
+ end
614
+
615
+ it 'makes both right corners at once' do
616
+ str = @sheet.corners(:left => 15.px)
617
+ str.should include "border-bottom-left-radius: 15px"
618
+ str.should include "-moz-border-radius-bottomleft: 15px"
619
+ str.should include "-webkit-border-bottom-left-radius: 15px"
620
+ str.should include "border-top-left-radius: 15px"
621
+ str.should include "-moz-border-radius-topleft: 15px"
622
+ str.should include "-webkit-border-top-left-radius: 15px"
623
+ end
624
+ end
625
+
626
+ describe '#shadow' do
627
+ it 'build declarations for all three browser types' do
628
+ str = @sheet.shadow
629
+ str.should match(/^box-shadow/)
630
+ str.should include '-webkit-box-shadow'
631
+ str.should include '-moz-box-shadow'
632
+ end
633
+
634
+ it 'has good defaults' do
635
+ @sheet.shadow.should include "0.25em 0.25em 0.25em black"
636
+ end
637
+
638
+ it 'uses the color when provided' do
639
+ str = @sheet.shadow(:color => '#666')
640
+ str.should include '#666'
641
+ str.should_not include 'black'
642
+ end
643
+
644
+ it 'uses the horizontal offset when provided' do
645
+ @sheet.shadow(:horizontal_offset => 20.px).should include "20px 0.25em 0.25em black"
646
+ end
647
+
648
+ it 'uses the vertical offset when provided' do
649
+ @sheet.shadow(:vertical_offset => 10.px).should include "0.25em 10px 0.25em black"
650
+ end
651
+
652
+ it 'uses the blur when provided' do
653
+ @sheet.shadow(:blur => 15.px).should include "0.25em 0.25em 15px black"
654
+ end
655
+
656
+ it 'will make an inner shadow' do
657
+ @sheet.shadow(:inner => true).should include "inset 0.25em 0.25em 0.25em black"
658
+ end
659
+ end
660
+
661
+ describe 'gradient' do
662
+ it 'requires a start and end color' do
663
+ lambda{ @sheet.gradient }.should raise_error(ArgumentError, "gradient styles require a :start and :end color")
664
+ end
665
+
666
+ it 'builds the necessary declarations' do
667
+ @sheet.gradient(:start => :white, :end => :black).should include(
668
+ "background: black",
669
+ "background: -webkit-gradient",
670
+ "background: -moz-linear-gradient"
671
+ )
672
+ end
673
+
674
+ describe 'direction' do
675
+ it 'defaults from top to bottom' do
676
+ @sheet.gradient(:start => :white, :end => :black).should include(
677
+ "linear, left top, left bottom",
678
+ "linear-gradient(top"
679
+ )
680
+ end
681
+
682
+ it 'makes from left to right' do
683
+ @sheet.gradient(:start => :white, :end => :black, :from => :left).should include(
684
+ "linear, left top, right top",
685
+ "linear-gradient(left"
686
+ )
687
+ end
688
+ end
689
+ end
690
+ end
517
691
 
518
692
  class StyleSheet < StyleTrain::Sheet
519
693
  def content
data/spec/theme_spec.rb CHANGED
@@ -4,16 +4,42 @@ Theme = StyleTrain::Theme unless defined?( Theme )
4
4
 
5
5
  describe Theme do
6
6
  class MyTheme < Theme
7
- required_keys :foo, :bar
7
+ required_keys :foo, :bar, :zardoz
8
+ defaults :zardoz => 'sexy'
8
9
  end
9
10
 
10
- describe 'Theme.required_keys' do
11
- it 'stores the values' do
12
- MyTheme.instance_eval('@required_keys').should == [:foo, :bar]
11
+ describe 'requiring keys' do
12
+ describe '#require_keys' do
13
+ it 'stores the values' do
14
+ MyTheme.instance_eval('@required_keys').should == [:foo, :bar, :zardoz]
15
+ end
16
+
17
+ it 'retreives the keys when no argument is supplied' do
18
+ MyTheme.required_keys.should == [:foo, :bar, :zardoz]
19
+ end
13
20
  end
14
21
 
15
- it 'retreives the keys when no argument is supplied' do
16
- MyTheme.required_keys.should == [:foo, :bar]
22
+ describe '#defaults' do
23
+ before :all do
24
+ @theme = MyTheme.new(:orange_red, :foo => 'orange', :bar => 'white')
25
+ end
26
+
27
+ it 'store the values' do
28
+ MyTheme.instance_eval('@defaults').should == Gnash.new(:zardoz => 'sexy')
29
+ end
30
+
31
+ it 'retrieves the hash when called without an argument' do
32
+ MyTheme.defaults.should == Gnash.new(:zardoz => 'sexy')
33
+ end
34
+
35
+ it 'adds defaults to the value hash' do
36
+ @theme[:zardoz].should == 'sexy'
37
+ end
38
+
39
+ it 'does not override values with the same key' do
40
+ theme = MyTheme.new(:red_orange, :foo => 'red', :bar => 'white', :zardoz => 'not all that')
41
+ theme[:zardoz].should == 'not all that'
42
+ end
17
43
  end
18
44
  end
19
45
 
@@ -48,7 +74,21 @@ describe Theme do
48
74
 
49
75
  it 'sets the value hash to value_hash accessor' do
50
76
  theme = MyTheme.new(:maroon, :foo => 'maroon', :bar => 'white')
51
- theme.value_hash.should == Gnash.new({:foo => 'maroon', :bar => 'white'})
77
+ theme.value_hash.should == Gnash.new({:foo => 'maroon', :bar => 'white', :zardoz => 'sexy'})
78
+ end
79
+
80
+ describe 'with palette' do
81
+ before :all do
82
+ @theme = MyTheme.new(:substitutor, {:foo => :blue, :bar => :white}, {:blue => 'true blue', :white => 'off sometimes'})
83
+ end
84
+
85
+ it "will save the pallete when it finds that argument" do
86
+ @theme.palette.should == {:blue => 'true blue', :white => 'off sometimes'}
87
+ end
88
+
89
+ it 'will substitue symbols for pallete values with the same key' do
90
+ @theme.value_hash.should == Gnash.new({:foo => 'true blue', :bar => 'off sometimes', :zardoz => 'sexy'})
91
+ end
52
92
  end
53
93
  end
54
94
 
data/style_train.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{style_train}
8
- s.version = "0.2.1"
8
+ s.version = "0.2.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Kane Baccigalupi"]
12
- s.date = %q{2011-02-19}
12
+ s.date = %q{2011-02-23}
13
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
14
  s.email = %q{baccigalupi@gmail.com}
15
15
  s.extra_rdoc_files = [
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: style_train
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 17
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 1
10
- version: 0.2.1
9
+ - 3
10
+ version: 0.2.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Kane Baccigalupi
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-02-19 00:00:00 -08:00
18
+ date: 2011-02-23 00:00:00 -08:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency