images_gallery 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/Rakefile +10 -1
  4. data/lib/images_gallery/generator.rb +16 -1
  5. data/lib/images_gallery/models/collection.rb +4 -0
  6. data/lib/images_gallery/models/image.rb +9 -5
  7. data/lib/images_gallery/models/source.rb +8 -0
  8. data/lib/images_gallery/templates/_thumbnails.html.erb +3 -2
  9. data/lib/images_gallery/templates/layout.html.erb +1 -1
  10. data/lib/images_gallery/version.rb +1 -1
  11. data/lib/images_gallery/views/base.rb +6 -4
  12. data/lib/images_gallery/views/iso.rb +30 -0
  13. data/lib/images_gallery/views/model.rb +1 -0
  14. data/spec/features/iso_pages/canon_eos_20d_iso_100_page_spec.rb +14 -0
  15. data/spec/features/iso_pages/lux_d_3_iso_100_page_spec.rb +14 -0
  16. data/spec/features/iso_pages/lux_d_3_iso_200_page_spec.rb +14 -0
  17. data/spec/features/models_pages/canon_eos_20d_page_spec.rb +7 -0
  18. data/spec/features/models_pages/lux_d_3_page_spec.rb +11 -0
  19. data/spec/lib/images_gallery/models/collection_spec.rb +1 -0
  20. data/spec/lib/images_gallery/models/source_spec.rb +7 -2
  21. data/spec/lib/images_gallery/views/iso_spec.rb +12 -0
  22. data/spec/support/spec_for_image_interface.rb +4 -0
  23. data/spec/support/spec_for_iso_page.rb +15 -0
  24. data/spec/support/spec_for_view_interface.rb +49 -0
  25. data/spec/tmp/canon.html +5 -3
  26. data/spec/tmp/canon/canon_eos_20d.html +9 -1
  27. data/spec/tmp/canon/canon_eos_20d/100.html +77 -0
  28. data/spec/tmp/canon/canon_eos_400d_digital.html +9 -1
  29. data/spec/tmp/canon/canon_eos_400d_digital/200.html +77 -0
  30. data/spec/tmp/fuji_photo_film_co_ltd.html +3 -2
  31. data/spec/tmp/fuji_photo_film_co_ltd/slp1000se.html +9 -1
  32. data/spec/tmp/fuji_photo_film_co_ltd/slp1000se/speed_ratings_unknown.html +77 -0
  33. data/spec/tmp/fujifilm.html +3 -2
  34. data/spec/tmp/fujifilm/finepix_s6500fd.html +9 -1
  35. data/spec/tmp/fujifilm/finepix_s6500fd/400.html +77 -0
  36. data/spec/tmp/index.html +21 -11
  37. data/spec/tmp/leica.html +11 -6
  38. data/spec/tmp/leica/d_lux_3.html +37 -1
  39. data/spec/tmp/leica/d_lux_3/100.html +87 -0
  40. data/spec/tmp/leica/d_lux_3/200.html +77 -0
  41. data/spec/tmp/leica/d_lux_3/800.html +77 -0
  42. data/spec/tmp/nikon_corporation.html +3 -2
  43. data/spec/tmp/nikon_corporation/nikon_d80.html +9 -1
  44. data/spec/tmp/nikon_corporation/nikon_d80/100.html +77 -0
  45. data/spec/tmp/panasonic.html +5 -3
  46. data/spec/tmp/panasonic/dmc_fz30.html +15 -1
  47. data/spec/tmp/panasonic/dmc_fz30/80.html +82 -0
  48. data/spec/tmp/unknown_make.html +5 -3
  49. data/spec/tmp/unknown_make/unknown_model.html +15 -1
  50. data/spec/tmp/unknown_make/unknown_model/speed_ratings_unknown.html +82 -0
  51. metadata +80 -35
  52. data/spec/support/spec_for_view_inerface.rb +0 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 67e420173590772158f6bab51506ccd9a836fe5c
4
- data.tar.gz: d53ff9a4c056c12d17d31396b8325841ad16111e
3
+ metadata.gz: 9c7660b3a472fe00fb56538c5c8fc8c7f6773e02
4
+ data.tar.gz: 861279385d115536a7d833e6f539da39c14dbc07
5
5
  SHA512:
6
- metadata.gz: 74de38ecf7c3ab952260a7403218354f05eccb271310f77b05872a83b1aa89555c91a6092f3b99bbaf2c6e90dd19ef6f0f2aa459773ea968fba535f3f607175e
7
- data.tar.gz: 01e3e36847c68a09f17f8892c793898788b28087f0e2933e2ac1ec41d3aa66dd17875b5166bff707c6df2993633e56e56c30c339479821e6cfcda42579995480
6
+ metadata.gz: c57e8b3352d328f3226d77bc597aea7327c7fcf36a9bca5aed750710a422fd02c9f3280dc625f84059a9812e19e1f2395b6abd4f422418c7cb9a23ea1503608e
7
+ data.tar.gz: 2316bca9500ad182e6a03079c7bd2f46b4472cafd67142dac52b594b4b0429ca7c3df3825548f7dce1bcb24a903ae5d19b661f67ab71073d704514f9db8adccb
data/README.md CHANGED
@@ -59,7 +59,7 @@ The `ImageGallery::Source` relies on the **LibXML** SAX parser to extract the im
59
59
  About
60
60
  -----
61
61
 
62
- This kata aims at writing a command-line tool to process **large** XML files which contain images metadata. Part of that metadata is relevant, and the images gallery should allow to preview a collection of thumbnails classified by camera **make** and **model**.
62
+ This kata aims at writing a command-line tool to process **large** XML files which contain images metadata. Part of that metadata is relevant, and the images gallery should allow to preview a collection of thumbnails classified by camera **make**, **model** and **ISO speed ratings**.
63
63
 
64
64
  Because the images collections can be really large, [care has been taken][parser] to avoid loading the XML document in memory while parsing it.
65
65
 
@@ -67,7 +67,7 @@ Because the images collections can be really large, [care has been taken][parser
67
67
 
68
68
  Yet huges collections to review do also mean you probably don't want to review them without involving your team. That's to say the images gallery deployment is a key aspect of the task at hand, and keeping the files tree as simple as possible is a way to make the deployments as straightforward as possible. No external CSS, nor font, nor javascipts then.
69
69
 
70
- The views/templates pattern makes the design extensible, this galleries generator is no <abbr title="Content Management System">CMS</abbr> however! Priority has been given to simplify as much as possible the rendering engine task. Plain ERb should keep the HTML generation fast, while a basic partials system ensures that adding front-end features remains [a _pomodoro_-sized task][pomodoro].
70
+ The views/templates pattern makes the design extensible, this galleries generator is no <abbr title="Content Management System">CMS</abbr> however! Priority has been given to simplify as much as possible the rendering engine task. Plain ERb should keep the HTML generation fast, while a basic partials system ensures that adding a few front-end features remains [a _pomodoro_-sized task][pomodoro]. (If more features would to be added, however, the views mechanics and the templates management should be refined - see the naviagtion links generation for example.)
71
71
 
72
72
  [pomodoro]: https://github.com/gonzalo-bulnes/kata-images_gallery_generator/commit/a90590e63f65d0b166c93e709a17a267c9ec119f
73
73
 
data/Rakefile CHANGED
@@ -1,3 +1,4 @@
1
+ require 'html/proofer'
1
2
  require 'rainbow'
2
3
  require 'rspec/core/rake_task'
3
4
 
@@ -21,4 +22,12 @@ rescue LoadError
21
22
  end
22
23
  end
23
24
 
24
- task default: [:spec, :inch]
25
+ namespace :validate do
26
+ desc 'Verify HTML files are valid.'
27
+ task :html do
28
+ system 'images_gallery generate spec/fixtures/works.xml spec/tmp > /dev/null'
29
+ HTML::Proofer.new('spec/tmp', disable_external: true, check_html: true).run
30
+ end
31
+ end
32
+
33
+ task default: [:spec, 'validate:html', :inch]
@@ -4,6 +4,7 @@ require 'images_gallery/models/source'
4
4
  require 'images_gallery/views/index'
5
5
  require 'images_gallery/views/make'
6
6
  require 'images_gallery/views/model'
7
+ require 'images_gallery/views/iso'
7
8
 
8
9
  module ImagesGallery
9
10
  class Generator
@@ -44,6 +45,15 @@ module ImagesGallery
44
45
  images_by_model << image
45
46
  view = Views::Model.new(images_by_model)
46
47
  files[view.file_identifier(image.make, image.model)] = view.render
48
+
49
+ images_by_model.iso_values.each do |iso_value|
50
+ images_by_iso_value = Models::Collection.new
51
+ images_by_model.select{ |image| image.iso == iso_value }.each do |image|
52
+ images_by_iso_value << image
53
+ view = Views::ISO.new(images_by_iso_value)
54
+ files[view.file_identifier(image.make, image.model, image.iso)] = view.render
55
+ end
56
+ end
47
57
  end
48
58
  end
49
59
  end
@@ -56,12 +66,17 @@ module ImagesGallery
56
66
  dir_path = "#{target}/#{name}".gsub('//', '/')
57
67
  file_path = dir_path + '.html'
58
68
  @index_path = file_path if name == 'index'
59
- FileUtils.mkdir_p(dir_path) unless File.exists?(dir_path) || (name == 'index')
69
+ FileUtils.mkdir_p(parent(dir_path)) unless File.exists?(dir_path) || (name == 'index')
60
70
  File.open(file_path, 'w') do |file|
61
71
  file.write content
62
72
  end
63
73
  end
64
74
  @index_path
65
75
  end
76
+
77
+ def parent(dir_path)
78
+ return dir_path.match('(.*)\/.*$').captures.first unless dir_path.match('(.*)\/.*$').nil?
79
+ '.'
80
+ end
66
81
  end
67
82
  end
@@ -12,6 +12,10 @@ module ImagesGallery
12
12
  map { |image| image.model }.uniq.sort
13
13
  end
14
14
 
15
+ def iso_values
16
+ map { |image| image.iso }.uniq.sort
17
+ end
18
+
15
19
  end
16
20
  end
17
21
  end
@@ -2,7 +2,15 @@ module ImagesGallery
2
2
  module Models
3
3
  class Image
4
4
 
5
- attr_accessor :id, :src, :make, :model
5
+ attr_accessor :id, :iso, :make, :model, :src
6
+
7
+ def description
8
+ "Image #{@id}"
9
+ end
10
+
11
+ def iso
12
+ @iso || 'speed ratings unknown'
13
+ end
6
14
 
7
15
  def make
8
16
  @make || 'Unknown Make'
@@ -12,10 +20,6 @@ module ImagesGallery
12
20
  @model || 'Unknown Model'
13
21
  end
14
22
 
15
- def description
16
- "Image #{@id}"
17
- end
18
-
19
23
  end
20
24
  end
21
25
  end
@@ -66,6 +66,10 @@ module ImagesGallery
66
66
  @current_image.id = @current_id
67
67
  end
68
68
 
69
+ if element == 'iso_speed_ratings'
70
+ @current_image.iso = @current_iso
71
+ end
72
+
69
73
  if element == 'make'
70
74
  @current_image.make = @current_make
71
75
  end
@@ -86,6 +90,10 @@ module ImagesGallery
86
90
  @current_id = char
87
91
  end
88
92
 
93
+ if @current_element == 'iso_speed_ratings'
94
+ @current_iso = char
95
+ end
96
+
89
97
  if @current_element == 'make'
90
98
  @current_make = char
91
99
  end
@@ -2,10 +2,11 @@
2
2
  <% images.each do |image| %>
3
3
  <div class="grid-item">
4
4
  <img alt="<%= image.description %>" src="<%= image.src %>"/>
5
- <% unless depth == 1 %>
6
- <a class="grid-item-details" href="<%= link_to(depth, image.make, image.model) %>" title="Browse all the <%= image.model %> images.">
5
+ <% unless depth > 1 %>
6
+ <a class="grid-item-details" href="<%= link_to(depth, image.make, image.model, image.iso) %>" title="Browse all the <%= image.model %> @ ISO <%= image.iso %> images.">
7
7
  <div><%= image.make %></div>
8
8
  <div><%= image.model %></div>
9
+ <div><small>ISO <%= image.iso %></small></div>
9
10
  </a>
10
11
  <% end %>
11
12
  </div>
@@ -35,7 +35,7 @@
35
35
  color: #333;
36
36
  font-size: .8rem;
37
37
  font-variant: small-caps;
38
- height: 3rem;
38
+ height: 4rem;
39
39
  left: 0;
40
40
  line-height: 1.2rem;
41
41
  opacity: 0;
@@ -1,3 +1,3 @@
1
1
  module ImagesGallery
2
- VERSION = '1.0.1'
2
+ VERSION = '1.1.0'
3
3
  end
@@ -41,15 +41,17 @@ module ImagesGallery
41
41
  ERB.new(File.new(template).read).result(binding)
42
42
  end
43
43
 
44
- def link_to(depth, make, model=nil)
45
- ('../' * depth) + file_identifier(make, model) + '.html'
44
+ def link_to(depth, make, model=nil, iso_value=nil)
45
+ ('../' * depth) + file_identifier(make, model, iso_value) + '.html'
46
46
  end
47
47
 
48
- def file_identifier(make, model=nil)
48
+ def file_identifier(make, model=nil, iso_value=nil)
49
49
  if model.nil?
50
50
  "#{make.to_filename}"
51
- else
51
+ elsif iso_value.nil?
52
52
  "#{make.to_filename}/#{model.to_filename}"
53
+ else
54
+ "#{make.to_filename}/#{model.to_filename}/#{iso_value.to_filename}"
53
55
  end
54
56
  end
55
57
  end
@@ -0,0 +1,30 @@
1
+ require 'erb'
2
+
3
+ require 'images_gallery/views/base'
4
+
5
+ module ImagesGallery
6
+ module Views
7
+ class ISO < Base
8
+
9
+ attr_reader :depth, :links, :iso, :make, :model, :sample_images, :title
10
+ private :depth, :links, :iso, :make, :model, :sample_images, :title
11
+
12
+ def initialize(images)
13
+ super()
14
+
15
+ @depth = 2
16
+ @make = images.first.make
17
+ @model = images.first.model
18
+ @iso = images.first.iso
19
+ @links = [{ name: "Browse all the images", href: link_to(depth, 'index') }]
20
+ @links << { name: "Browse all the #{model} images", href: link_to(depth, make, model) }
21
+ @sample_images = images
22
+ @title = "Images by (#{make}) #{model} @ ISO #{iso}"
23
+ end
24
+
25
+ def template
26
+ File.expand_path('../../templates/layout.html.erb', __FILE__)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -17,6 +17,7 @@ module ImagesGallery
17
17
  @model = images.first.model
18
18
  @links = [{ name: "Browse all the images", href: link_to(depth, 'index') }]
19
19
  @links << { name: "Browse all the #{make} images", href: link_to(depth, make) }
20
+ @links += images.iso_values.map{ |iso_value| { name: "ISO #{iso_value}", href: link_to(depth, make, model, iso_value) } }
20
21
  @sample_images = images
21
22
  @title = "Images by (#{make}) #{model}"
22
23
  end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'The Canon EOS 20D @ ISO 100 page', type: :feature do
4
+
5
+ let!(:generator) { ImagesGallery::Generator.new }
6
+
7
+ before(:each) do
8
+ generator.run('spec/fixtures/works.xml', 'spec/tmp/')
9
+ visit '/canon/canon_eos_20d/100.html'
10
+ end
11
+
12
+ it_behaves_like('an images gallery', 1, header_selector, navigation_selector, title_selector)
13
+ it_behaves_like('an ISO page', 'canon', 'canon_eos_20d', navigation_selector)
14
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'The LUX-D 3 @ ISO 100 page', type: :feature do
4
+
5
+ let!(:generator) { ImagesGallery::Generator.new }
6
+
7
+ before(:each) do
8
+ generator.run('spec/fixtures/works.xml', 'spec/tmp/')
9
+ visit '/leica/d_lux_3/100.html'
10
+ end
11
+
12
+ it_behaves_like('an images gallery', 3, header_selector, navigation_selector, title_selector)
13
+ it_behaves_like('an ISO page', 'leica', 'd_lux_3', navigation_selector)
14
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'The LUX-D 3 @ ISO 200 page', type: :feature do
4
+
5
+ let!(:generator) { ImagesGallery::Generator.new }
6
+
7
+ before(:each) do
8
+ generator.run('spec/fixtures/works.xml', 'spec/tmp/')
9
+ visit '/leica/d_lux_3/200.html'
10
+ end
11
+
12
+ it_behaves_like('an images gallery', 1, header_selector, navigation_selector, title_selector)
13
+ it_behaves_like('an ISO page', 'leica', 'd_lux_3', navigation_selector)
14
+ end
@@ -11,4 +11,11 @@ describe 'The Canon EOS 20D model page', type: :feature do
11
11
 
12
12
  it_behaves_like('an images gallery', 1, header_selector, navigation_selector, title_selector)
13
13
  it_behaves_like('a model page', 'canon', navigation_selector)
14
+
15
+ describe 'navigation' do
16
+
17
+ it 'contains a link to the ISO 100 page' do
18
+ expect(page).to have_selector "#{navigation_selector} a[href='../canon/canon_eos_20d/100.html']"
19
+ end
20
+ end
14
21
  end
@@ -11,4 +11,15 @@ describe 'The LUX-D 3 model page', type: :feature do
11
11
 
12
12
  it_behaves_like('an images gallery', 5, header_selector, navigation_selector, title_selector)
13
13
  it_behaves_like('a model page', 'leica', navigation_selector)
14
+
15
+ describe 'navigation' do
16
+
17
+ it 'contains a link to the ISO 200 page' do
18
+ expect(page).to have_selector "#{navigation_selector} a[href='../leica/d_lux_3/200.html']"
19
+ end
20
+
21
+ it 'contains a link to the ISO 100 page' do
22
+ expect(page).to have_selector "#{navigation_selector} a[href='../leica/d_lux_3/100.html']"
23
+ end
24
+ end
14
25
  end
@@ -7,6 +7,7 @@ describe 'Models::Collection' do
7
7
 
8
8
  it_behaves_like 'a collection'
9
9
 
10
+ it { expect(collection).to respond_to :iso_values }
10
11
  it { expect(collection).to respond_to :makes }
11
12
  it { expect(collection).to respond_to :models }
12
13
 
@@ -25,12 +25,17 @@ describe 'Models::Source' do
25
25
  source.parse
26
26
  source.images.each do |image|
27
27
 
28
- # There is some duplication here that I couldn't remove.
28
+ # There is some duplication here that I couldn't remove because
29
+ # the shared specs do not allow to inject the object under test.
30
+ #
31
+ # I did copy the examples from the image interface spec.
29
32
  # See spec/support/spec_for_image_interface.
30
-
33
+ #
34
+ # The following examples mean in fact:
31
35
  #it_behaves_like 'an image'
32
36
 
33
37
  expect(image).to respond_to :description
38
+ expect(image).to respond_to :iso
34
39
  expect(image).to respond_to :make
35
40
  expect(image).to respond_to :model
36
41
  expect(image).to respond_to :src
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ module ImagesGallery
4
+ describe 'Views::ISO' do
5
+
6
+ let(:data) { images_collection }
7
+ let(:view) { Views::ISO.new(data) }
8
+
9
+ it_behaves_like 'a view'
10
+
11
+ end
12
+ end
@@ -15,4 +15,8 @@ RSpec.shared_examples 'an image' do
15
15
  it 'responds to :src' do
16
16
  expect(image).to respond_to :src
17
17
  end
18
+
19
+ it 'responds to :iso' do
20
+ expect(image).to respond_to :iso
21
+ end
18
22
  end
@@ -0,0 +1,15 @@
1
+ RSpec.shared_examples 'an ISO page' do |make, model, navigation_selector|
2
+
3
+ describe 'navigation' do
4
+
5
+ it 'contains a link to the index page' do
6
+ expect(page).to have_selector "#{navigation_selector} a[href='../../index.html']"
7
+ end
8
+
9
+ it 'contains a link to the model page' do
10
+ expect(page).to have_selector "#{navigation_selector} a[href='../../#{make}/#{model}.html']"
11
+ end
12
+
13
+ it 'contains a link to the make page'
14
+ end
15
+ end
@@ -0,0 +1,49 @@
1
+ RSpec.shared_examples 'a view' do
2
+
3
+ it 'responds to :link_to' do
4
+ expect(view).to respond_to :link_to
5
+ end
6
+
7
+ it 'responds to :render' do
8
+ expect(view).to respond_to :render
9
+ end
10
+
11
+ it 'responds to :template' do
12
+ expect(view).to respond_to :template
13
+ end
14
+
15
+ it 'defines :template' do
16
+ expect { view.template }.not_to raise_error
17
+ end
18
+
19
+ context 'when built with no data' do
20
+
21
+ it 'exits gracefully (?)'
22
+ end
23
+
24
+ describe '#link_to' do
25
+
26
+ let(:depth) { 1 }
27
+
28
+ context 'when provided a depth and a make' do
29
+
30
+ it 'generates a make page URL' do
31
+ expect(view.link_to(depth, 'make')).to eq '../make.html'
32
+ end
33
+ end
34
+
35
+ context 'when provided a depth, a make and a model' do
36
+
37
+ it 'generates a model page URL' do
38
+ expect(view.link_to(depth, 'make', 'model')).to eq '../make/model.html'
39
+ end
40
+ end
41
+
42
+ context 'when provided a depth, a make, a model, and an ISO value' do
43
+
44
+ it 'generates an ISO page' do
45
+ expect(view.link_to(depth, 'make', 'model', 'iso_value')).to eq '../make/model/iso_value.html'
46
+ end
47
+ end
48
+ end
49
+ end
@@ -35,7 +35,7 @@
35
35
  color: #333;
36
36
  font-size: .8rem;
37
37
  font-variant: small-caps;
38
- height: 3rem;
38
+ height: 4rem;
39
39
  left: 0;
40
40
  line-height: 1.2rem;
41
41
  opacity: 0;
@@ -71,9 +71,10 @@
71
71
  <div class="grid-item">
72
72
  <img alt="Image 2041" src="http://ih1.redbubble.net/work.2041.1.flat,135x135,075,f.jpg"/>
73
73
 
74
- <a class="grid-item-details" href="canon/canon_eos_20d.html" title="Browse all the Canon EOS 20D images.">
74
+ <a class="grid-item-details" href="canon/canon_eos_20d/100.html" title="Browse all the Canon EOS 20D @ ISO 100 images.">
75
75
  <div>Canon</div>
76
76
  <div>Canon EOS 20D</div>
77
+ <div><small>ISO 100</small></div>
77
78
  </a>
78
79
 
79
80
  </div>
@@ -81,9 +82,10 @@
81
82
  <div class="grid-item">
82
83
  <img alt="Image 777577" src="http://ih1.redbubble.net/work.777577.1.flat,135x135,075,f.jpg"/>
83
84
 
84
- <a class="grid-item-details" href="canon/canon_eos_400d_digital.html" title="Browse all the Canon EOS 400D DIGITAL images.">
85
+ <a class="grid-item-details" href="canon/canon_eos_400d_digital/200.html" title="Browse all the Canon EOS 400D DIGITAL @ ISO 200 images.">
85
86
  <div>Canon</div>
86
87
  <div>Canon EOS 400D DIGITAL</div>
88
+ <div><small>ISO 200</small></div>
87
89
  </a>
88
90
 
89
91
  </div>