bread-basket 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +4 -0
  3. data/.rubocop.yml +18 -0
  4. data/.travis.yml +4 -1
  5. data/Gemfile +1 -1
  6. data/Guardfile +7 -2
  7. data/README.md +28 -17
  8. data/Rakefile +13 -6
  9. data/bin/bread-basket +14 -0
  10. data/bread-basket.gemspec +29 -24
  11. data/lib/bread/basket.rb +12 -6
  12. data/lib/bread/basket/cli.rb +10 -0
  13. data/lib/bread/basket/poster.rb +38 -0
  14. data/lib/bread/basket/poster/block_code_handler.rb +50 -0
  15. data/lib/bread/basket/poster/block_renderer.rb +14 -0
  16. data/lib/bread/basket/poster/box.rb +119 -0
  17. data/lib/bread/basket/poster/box_checker.rb +60 -0
  18. data/lib/bread/basket/poster/columns.rb +90 -0
  19. data/lib/bread/basket/poster/css_reader.rb +130 -0
  20. data/lib/bread/basket/poster/dimensions_helper.rb +123 -0
  21. data/lib/bread/basket/poster/header_callback.rb +29 -0
  22. data/lib/bread/basket/poster/header_maker.rb +74 -0
  23. data/lib/bread/basket/poster/image_box.rb +93 -0
  24. data/lib/bread/basket/poster/layout.rb +108 -0
  25. data/lib/bread/basket/poster/pdf_builder.rb +113 -0
  26. data/lib/bread/basket/poster/poster_maker.rb +55 -0
  27. data/lib/bread/basket/poster/prawn_patches/column_box.rb +17 -0
  28. data/lib/bread/basket/poster/text_renderer.rb +89 -0
  29. data/lib/bread/basket/poster/units_helper.rb +39 -0
  30. data/lib/bread/basket/version.rb +1 -1
  31. data/samples/block_sample.css +86 -0
  32. data/samples/flow_sample.css +68 -0
  33. data/samples/ipsum.jpg +0 -0
  34. data/samples/lorem.jpg +0 -0
  35. data/samples/lorem_block.md +86 -0
  36. data/samples/lorem_flow.md +58 -0
  37. data/samples/lorem_flow.pdf +3834 -6
  38. data/samples/sample.md +59 -0
  39. data/samples/simple.css +19 -0
  40. data/samples/simple.md +3 -0
  41. data/samples/ucair_logo.png +0 -0
  42. data/spec/cli_spec.rb +13 -0
  43. data/spec/poster/block_code_handler_spec.rb +47 -0
  44. data/spec/poster/box_spec.rb +114 -0
  45. data/spec/poster/columns_spec.rb +64 -0
  46. data/spec/poster/css_reader_spec.rb +115 -0
  47. data/spec/poster/header_maker_spec.rb +49 -0
  48. data/spec/poster/image_box_spec.rb +69 -0
  49. data/spec/poster/layout_spec.rb +75 -0
  50. data/spec/poster/pdf_builder_spec.rb +60 -0
  51. data/spec/poster/poster_maker_spec.rb +15 -0
  52. data/spec/poster/test_files/bad_file.md +1 -0
  53. data/spec/poster/test_files/basic_block.css +14 -0
  54. data/spec/poster/test_files/basic_flow.css +31 -0
  55. data/spec/poster/test_files/block_code_test.css +13 -0
  56. data/spec/poster/test_files/builder.css +39 -0
  57. data/spec/poster/test_files/circular.css +39 -0
  58. data/spec/poster/test_files/dragon.png +0 -0
  59. data/spec/poster/test_files/fitted_image.css +39 -0
  60. data/spec/poster/test_files/good_file.md +5 -0
  61. data/spec/poster/test_files/good_file.pdf +0 -0
  62. data/spec/poster/test_files/header_test.css +22 -0
  63. data/spec/poster/test_files/nearly_empty.css +10 -0
  64. data/spec/poster/test_files/self_referential.css +108 -0
  65. data/spec/poster/test_files/ucair_logo.png +0 -0
  66. data/spec/poster/text_renderer_spec.rb +54 -0
  67. data/spec/poster/units_helper_spec.rb +36 -0
  68. data/spec/spec_helper.rb +6 -0
  69. metadata +212 -34
  70. data/bread-basket-0.0.1.gem +0 -0
  71. data/spec/basket_spec.rb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8e88de24214b514b997f49898747732ceacc0a73
4
- data.tar.gz: 50c00bbc435f9797d45079dfb4740c1588f421d4
3
+ metadata.gz: 9cd2a8c7a51afc5eccbd1e627a982d10e59c1501
4
+ data.tar.gz: 4352f64d75add2341aafd3c9bc06f45bd475b4bf
5
5
  SHA512:
6
- metadata.gz: 444d8e8ec75f35a219cb09fe80da4b4abc8938ab358f7ace7e12b89d4b20388bd6ec6ab0d1b4fed20916eae3f1f019779c3f08766c19dbde0d57bf0e22cafccd
7
- data.tar.gz: 911ccad5a2c93f460a7ef50d0274a03afbbf7563cf25963838776edebae631ee5d3d9c656fb376991ce2565518e11ecc08982f9e2b3490a98d322117604e67e2
6
+ metadata.gz: d8c4cc7727a2a881a5e5a13b3be478a8d8628b2d065c6fd85367f23a684831e6decedd401422760d6d592a8eb94e5649e1b5fe33a62aab95d1e821f7814510b6
7
+ data.tar.gz: 92024548da731c38005e6d9ec119e30604b3a369756e4c347c61c9ed9d75e49931894f6c87ab470c119a928bab4f1ba653f6bfb7959c28bf06e4ab59f1cce361
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format progress
3
+ --order random
4
+ --require spec_helper
@@ -0,0 +1,18 @@
1
+ # This cop checks for top-level documentation of classes and modules.
2
+ Style/Documentation:
3
+ Enabled: false
4
+
5
+ # This cop checks for snake_case ruby file names.
6
+ # It is off because it triggers on ruby shebang.
7
+ Style/FileName:
8
+ Enabled: false
9
+
10
+ # This cop wisely checks for eval, but I use it carefully so
11
+ # it'll have to be silent
12
+ Lint/Eval:
13
+ Enabled: false
14
+
15
+ # My namespace puts methods 5 indents in 80->90
16
+ # many methods add at least 1 more indent 90->92
17
+ Metrics/LineLength:
18
+ Max: 92
@@ -2,9 +2,12 @@ language: ruby
2
2
  cache: bundler
3
3
 
4
4
  rvm:
5
- - jruby
6
5
  - 2.0.0
7
6
 
7
+ # Not sure why I need this!
8
+ before_install:
9
+ - 'gem install bundler'
10
+
8
11
  script: 'bundle exec rake'
9
12
 
10
13
  notifications:
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in bread-basket.gemspec
3
+ # Gem's dependencies are specified in bread-basket.gemspec
4
4
  gemspec
data/Guardfile CHANGED
@@ -1,11 +1,16 @@
1
1
  guard :rspec, cmd: 'bundle exec rspec' do
2
2
  # watch /lib/ files
3
- watch(%r{^lib/(.+).rb$}) do |m|
3
+ watch(/^lib\/(.+).rb$/) do |m|
4
4
  "spec/#{m[1]}_spec.rb"
5
5
  end
6
6
 
7
7
  # watch /spec/ files
8
- watch(%r{^spec/(.+).rb$}) do |m|
8
+ watch(/^spec\/(.+).rb$/) do |m|
9
9
  "spec/#{m[1]}.rb"
10
10
  end
11
11
  end
12
+
13
+ guard :rubocop do
14
+ watch(/.+\.rb$/)
15
+ watch(/(?:.+\/)?\.rubocop\.yml$/) { |m| File.dirname(m[0]) }
16
+ end
data/README.md CHANGED
@@ -1,36 +1,47 @@
1
1
  # Basket
2
+ [![Build Status](https://travis-ci.org/bread/bread-basket.svg?branch=master)](https://travis-ci.org/bread/bread-basket)
3
+ [![Coverage Status](https://coveralls.io/repos/bread/bread-basket/badge.svg?branch=master)](https://coveralls.io/r/bread/bread-basket?branch=master)
2
4
 
3
- Basket is a tool for publishing scientific findings. It's the last piece of the :bread: framework for scientific computing.
5
+ Basket is a tool for publishing scientific findings.
6
+ It's the last piece of the :bread: framework for scientific computing.
7
+ But it's the first thing I've tried to build in that framework.
4
8
 
5
- For now it just makes scientific posters. In the future thought it should help make figures, presentations, and maybe even full journal articles.
9
+ When the `Poster` module is finished it will make scientific posters.
10
+ In the future however, `bread-basket` should help make
11
+ figures, presentations, and maybe even full journal articles.
6
12
 
7
- ## Installation
13
+ ## Installation and Usage
8
14
 
9
- Add this line to your application's Gemfile:
15
+ Since :bread: hasn't been built (at all) yet, this little piece of the framework
16
+ is pretty lonely. So for now it's just a command-line utility
17
+ for making scientific posters. To use it, first get it into your Ruby environment with
10
18
 
11
- ```ruby
12
- gem 'bread-basket'
13
- ```
14
-
15
- And then execute:
19
+ $ gem install bread-basket
16
20
 
17
- $ bundle
21
+ (If you're brand new to Ruby and not so sure about the above line, I plan to put
22
+ an introduction to Ruby for scientists on the bread homepage. So just sit tight
23
+ until I get that built.)
18
24
 
19
- Or install it yourself as:
25
+ Once that's installed you should be able to convert a suitable markdown file
26
+ (with your poster's content) and stylesheet into a nice pdf like so
20
27
 
21
- $ gem install bread-basket
28
+ $ bread-basket poster my-poster.md
22
29
 
23
- ## Usage
30
+ and it will produce a pdf that you can take to the printers!
24
31
 
25
- The only tool in the Bread Basket is Posterize. You should call it from the command line with the path to your poster markdown file like so
32
+ For more information on how to write the markdown file for your poster
33
+ check out the example below, or email me. In the future a website will
34
+ provide some good documentation.
26
35
 
27
- $ posterize my-poster.md
36
+ ## Example
28
37
 
29
- and it will produce a pdf that you can take to the printers. For more information on how to write the markdown file for you poster check out the website (doesn't exist yet).
38
+ The samples folder contains an example poster `lorem_flow.md` along with the pdf
39
+ this software creates. Right now this is the only sample that works so go check it
40
+ out.
30
41
 
31
42
  ## Contributing
32
43
 
33
- 1. Fork it ( https://github.com/[my-github-username]/bread-basket/fork )
44
+ 1. Fork it ( https://github.com/bread/bread-basket/fork )
34
45
  2. Create your feature branch (`git checkout -b my-new-feature`)
35
46
  3. Commit your changes (`git commit -am 'Add some feature'`)
36
47
  4. Push to the branch (`git push origin my-new-feature`)
data/Rakefile CHANGED
@@ -1,10 +1,17 @@
1
1
  require 'rspec/core/rake_task'
2
- require "bundler/gem_tasks"
2
+ require 'bundler/gem_tasks'
3
+ require 'rubocop/rake_task'
3
4
 
4
5
  # Default directory to look in is `/specs`
5
- # Run with `rake spec`
6
- RSpec::Core::RakeTask.new(:spec) do |task|
7
- task.rspec_opts = ['--color', '--format', 'nested']
8
- end
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
9
9
 
10
- task :default => :spec
10
+ desc 'Run RuboCop on the lib directory'
11
+ RuboCop::RakeTask.new(:rubocop) do |task|
12
+ task.patterns = ['lib/bread/**/*.rb']
13
+ # only show the files with failures
14
+ task.formatters = ['files']
15
+ # don't abort rake on failure
16
+ task.fail_on_error = false
17
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Avoid running bundle exec by running this first instead!
4
+ lib_directory = File.expand_path('../../lib', __FILE__)
5
+ $LOAD_PATH << lib_directory
6
+
7
+ if File.exist?('Gemfile')
8
+ require 'bundler/setup'
9
+ Bundler.require
10
+ end
11
+
12
+ require 'bread/basket'
13
+
14
+ Bread::Basket::Cli.start(ARGV)
@@ -4,32 +4,37 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'bread/basket/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "bread-basket"
7
+ spec.name = 'bread-basket'
8
8
  spec.version = Bread::Basket::VERSION
9
- spec.authors = ["KC Erb"]
10
- spec.email = ["iamkcerb@gmail.com"]
11
- spec.summary = "The publication tool for bread"
12
- spec.description =
13
- 'Basket is a tool for publishing scientific findings. It\'s the last piece of ' +
14
- 'the :bread: framework for scientific computing.\n\nFor now it just makes' +
15
- 'scientific posters. In the future thought it should help make figures,' +
16
- ' presentations, and maybe even full journal articles.'
17
- spec.homepage = "https://github.com/bread/bread-basket"
18
- spec.license = "MIT"
9
+ spec.authors = ['KC Erb']
10
+ spec.email = ['iamkcerb@gmail.com']
11
+ spec.summary = 'The go-to publication tool for bread'
12
+ spec.description = 'bread-basket is still under development. This release ' \
13
+ 'contains only bare-bones functionality'
14
+ spec.homepage = 'https://github.com/bread/bread-basket'
15
+ spec.license = 'MIT'
19
16
 
20
17
  spec.files = `git ls-files -z`.split("\x0")
21
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
- spec.require_paths = ["lib"]
18
+ spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(/^(test|spec|features)\//)
20
+ spec.require_paths = ['lib']
24
21
 
25
- spec.add_development_dependency "bundler", "~> 1.7"
26
- spec.add_development_dependency "rake", "~> 10.0"
27
- spec.add_development_dependency "rspec", "~> 3.2"
28
- spec.add_development_dependency "rspec-nc", "~> 0"
29
- spec.add_development_dependency "guard", "~> 2.12"
30
- spec.add_development_dependency "guard-rspec", "~> 4.0"
31
- spec.add_development_dependency "pry", "~> 0.10"
32
- spec.add_development_dependency "pry-remote", "~> 0.1"
33
- spec.add_development_dependency "pry-nav", "~> 0.2"
34
- spec.add_development_dependency "coveralls", "~> 0.7"
22
+ spec.add_development_dependency 'bundler', '~> 1.9'
23
+ spec.add_development_dependency 'coveralls', '~> 0.7'
24
+ spec.add_development_dependency 'rake', '~> 10.4'
25
+ spec.add_development_dependency 'guard', '~> 2.12'
26
+ spec.add_development_dependency 'guard-rspec', '~> 4.5'
27
+ spec.add_development_dependency 'guard-rubocop', '~> 1.2'
28
+ spec.add_development_dependency 'pry', '~> 0.10'
29
+ spec.add_development_dependency 'pry-nav', '~> 0.2'
30
+ spec.add_development_dependency 'pry-remote', '~> 0.1'
31
+ spec.add_development_dependency 'rspec', '~> 3.2'
32
+ spec.add_development_dependency 'rspec-its', '~> 1.2'
33
+ spec.add_development_dependency 'rspec-nc', '~> 0'
34
+
35
+ spec.add_dependency 'css_parser', '~> 1.3'
36
+ spec.add_dependency 'fastimage', '~> 1.6'
37
+ spec.add_dependency 'prawn', '~> 2.0'
38
+ spec.add_dependency 'redcarpet', '~> 3.2'
39
+ spec.add_dependency 'thor', '~> 0.19'
35
40
  end
@@ -1,7 +1,13 @@
1
- require "bread/basket/version"
1
+ # gems
2
+ require 'yaml'
3
+ require 'thor'
4
+ require 'css_parser'
5
+ require 'prawn'
6
+ require 'prawn/measurement_extensions'
7
+ require 'fastimage'
8
+ require 'redcarpet'
2
9
 
3
- module Bread
4
- module Basket
5
- # Your code goes here...
6
- end
7
- end
10
+ # local
11
+ require 'bread/basket/version'
12
+ require 'bread/basket/cli'
13
+ require 'bread/basket/poster'
@@ -0,0 +1,10 @@
1
+ module Bread
2
+ module Basket
3
+ class Cli < Thor
4
+ desc 'poster FILENAME', 'Creates a scientific poster from FILENAME'
5
+ def poster(file)
6
+ Bread::Basket::Poster::PosterMaker.new(file)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,38 @@
1
+ require 'bread/basket/poster/prawn_patches/column_box'
2
+ require 'bread/basket/poster/header_callback'
3
+ require 'bread/basket/poster/header_maker'
4
+ require 'bread/basket/poster/text_renderer'
5
+ require 'bread/basket/poster/block_renderer'
6
+ require 'bread/basket/poster/poster_maker'
7
+ require 'bread/basket/poster/layout'
8
+ require 'bread/basket/poster/box_checker'
9
+ require 'bread/basket/poster/units_helper'
10
+ require 'bread/basket/poster/dimensions_helper'
11
+ require 'bread/basket/poster/box'
12
+ require 'bread/basket/poster/image_box'
13
+ require 'bread/basket/poster/columns'
14
+ require 'bread/basket/poster/css_reader'
15
+ require 'bread/basket/poster/pdf_builder'
16
+ require 'bread/basket/poster/block_code_handler'
17
+
18
+ module Bread
19
+ module Basket
20
+ module Poster
21
+ TEXT_RENDERER_OPTS = { fenced_code_blocks: true,
22
+ disable_indented_code_blocks: true,
23
+ underline: true,
24
+ highlight: true,
25
+ superscript: true,
26
+ tables: true }
27
+ class << self
28
+ attr_accessor :dir_path, :layout, :pdf, :current_styles, :body
29
+ end
30
+
31
+ # Default dir path, since in some specs this doesn't get set
32
+ # this is a code smell and is on the to do list.
33
+ dirname = File.dirname(__FILE__)
34
+ Poster.dir_path = File.expand_path('../../../', dirname) + '/spec/poster/test_files'
35
+ Poster.current_styles = {}
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,50 @@
1
+ module Bread
2
+ module Basket
3
+ module Poster
4
+ class BlockCodeHandler
5
+ attr_reader :pdf, :layout, :text_renderer
6
+
7
+ def initialize(pdf, layout, first_line, content)
8
+ @pdf = pdf
9
+ @layout = layout
10
+ @text_renderer = Redcarpet::Markdown.new(TextRenderer, TEXT_RENDERER_OPTS)
11
+ sort_input(first_line, content)
12
+ end
13
+
14
+ def sort_input(first_line, content)
15
+ case first_line
16
+ when /\A.*\.(jpg|jpeg|png)\Z/
17
+ create_image(first_line, content)
18
+ else
19
+ puts "Warning: Couldn't figure out what to do with #{content} block.\n"
20
+ end
21
+ end
22
+
23
+ # TODO: Get a lot of these values from the CSS
24
+ def create_image(image_src, caption)
25
+ image_path = Bread::Basket::Poster.dir_path + '/' + image_src
26
+ @columns_width = layout.columns[0].width
27
+ pdf.image image_path, width: @columns_width, position: :center
28
+ pdf.move_down 15
29
+ draw_caption(caption)
30
+ end
31
+
32
+ def draw_caption(caption)
33
+ top_left = [pdf.bounds.left + 20, pdf.cursor]
34
+ pdf.bounding_box(top_left, width: @columns_width - 40) do
35
+ # spin up a new renderer since this is called within one and Redcarpet
36
+ # doesn't allow this: https://github.com/vmg/redcarpet/issues/318
37
+ caption_content caption
38
+ end
39
+ end
40
+
41
+ def caption_content(caption)
42
+ pdf.stroke_bounds
43
+ pdf.move_down 15
44
+ text_renderer.render(caption)
45
+ pdf.move_down 36
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,14 @@
1
+ module Bread
2
+ module Basket
3
+ module Poster
4
+ class BlockRenderer < TextRenderer
5
+ attr_reader :pdf, :layout
6
+
7
+ # create pdf bounding box
8
+ def header(_text, _header_level)
9
+ # needs to be scss aware
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,119 @@
1
+ module Bread
2
+ module Basket
3
+ module Poster
4
+ class Box
5
+ include UnitsHelper
6
+ # Box does most of the heavy lifting of the self-referential css
7
+ # so it's a little confusing. It passes dimensions off to the dimensions
8
+ # helper and holds the methods for setting dimensions as either pending
9
+ # or determined and how to resolve those issues.
10
+ attr_reader :selector_name, :method_name, :layout, :specs,
11
+ :pending, :unfinished, :styles
12
+ attr_accessor :top, :left, :width, :height, :bottom, :right, :stretchy,
13
+ :content
14
+
15
+ def initialize(name, layout, specs = {})
16
+ fetch_names(name)
17
+ @layout = layout
18
+ @specs = specs
19
+ @styles = specs
20
+ @pending = []
21
+ @unfinished = []
22
+
23
+ setup_dimensions
24
+ layout.image_boxes << method_name if self.is_a? ImageBox
25
+ layout.boxes << selector_name
26
+ end
27
+
28
+ def fetch_names(name)
29
+ @selector_name = name
30
+ @method_name = name.sub('.', '').gsub('-', '_')
31
+ end
32
+
33
+ def setup_dimensions
34
+ DimensionsHelper.new(self, layout, specs)
35
+ layout.pending << selector_name unless pending.empty?
36
+ end
37
+
38
+ def try_to_resolve
39
+ pending.each do |dimension|
40
+ hash = send dimension
41
+ try_dimension hash
42
+ resolve_dimension(dimension, hash) if ready_to_resolve? hash
43
+ end
44
+ end
45
+
46
+ def try_dimension(dimensions_hash)
47
+ dimensions_hash[:pending].delete_if do |dimension_key, index|
48
+ value = layout.determined[dimension_key]
49
+ if value && value != :stretchy
50
+ command_arr = dimensions_hash[:command]
51
+ command_arr[index] = value
52
+ end
53
+ end
54
+ end
55
+
56
+ def resolve_dimension(dimension, hash)
57
+ command_string = hash[:command].join(' ')
58
+ value = eval command_string
59
+ instance_variable_set "@#{dimension}", value
60
+ pending.delete dimension
61
+ add_to_determined dimension, value
62
+ resolve_box if pending.empty?
63
+ end
64
+
65
+ def ready_to_resolve?(hash)
66
+ hash[:pending].empty? && safe?(hash[:command])
67
+ end
68
+
69
+ def safe?(command_array)
70
+ command_array.all? do |elem|
71
+ (elem.is_a? Numeric) || ([:+, :-, :/, :*, '(', ')'].include?(elem))
72
+ end
73
+ end
74
+
75
+ def add_to_determined(dimension_name, value)
76
+ name = method_name + '.' + dimension_name
77
+ instance_variable_set "@#{dimension_name}", value
78
+ layout.determined[name] = value
79
+ end
80
+
81
+ def resolve_box
82
+ layout.pending.delete selector_name
83
+ unfinished.each { |dimension| determine_missing dimension }
84
+ end
85
+ # Rubocop hates determine_missing
86
+ # rubocop:disable all
87
+ def determine_missing(missing_dimension)
88
+ value = case missing_dimension
89
+ when 'left'
90
+ right - width
91
+ when 'right'
92
+ left + width
93
+ when 'width'
94
+ right - left
95
+ when 'top'
96
+ bottom + height
97
+ when 'height'
98
+ top - bottom
99
+ when 'bottom'
100
+ top - height
101
+ end
102
+ add_to_determined missing_dimension, value
103
+ end
104
+ # rubocop:enable all
105
+ def inspect
106
+ str = ''
107
+ %w(top left width height bottom right).each do |dim|
108
+ str << "#{dim}: #{send(dim)}; "
109
+ end
110
+ str.strip
111
+ end
112
+
113
+ def stretchy?
114
+ !stretchy.nil?
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end