style_train 0.2.1 → 0.2.3

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/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