dry-view 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +15 -11
  3. data/CHANGELOG.md +23 -0
  4. data/Gemfile +6 -5
  5. data/README.md +8 -1
  6. data/benchmarks/templates/{button.erb → button.html.erb} +0 -0
  7. data/benchmarks/view.rb +3 -4
  8. data/bin/console +7 -0
  9. data/dry-view.gemspec +7 -6
  10. data/lib/dry/view/controller.rb +107 -0
  11. data/lib/dry/view/exposure.rb +61 -0
  12. data/lib/dry/view/exposures.rb +50 -0
  13. data/lib/dry/view/path.rb +40 -0
  14. data/lib/dry/view/renderer.rb +20 -28
  15. data/lib/dry/view/scope.rb +55 -0
  16. data/lib/dry/view/version.rb +1 -1
  17. data/lib/dry/view.rb +1 -1
  18. data/spec/fixtures/templates/empty.html.slim +1 -0
  19. data/spec/fixtures/templates/layouts/app.html.slim +1 -1
  20. data/spec/fixtures/templates/layouts/app.txt.erb +1 -1
  21. data/spec/fixtures/templates/parts_with_args/_box.html.slim +3 -0
  22. data/spec/fixtures/templates/parts_with_args.html.slim +3 -0
  23. data/spec/fixtures/templates/users/_tbody.html.slim +1 -1
  24. data/spec/fixtures/templates/users.html.slim +4 -4
  25. data/spec/fixtures/templates/users.txt.erb +0 -2
  26. data/spec/fixtures/templates/users_with_count.html.slim +5 -0
  27. data/spec/fixtures/templates_override/users.html.slim +5 -0
  28. data/spec/integration/exposures_spec.rb +178 -0
  29. data/spec/integration/view_spec.rb +83 -20
  30. data/spec/spec_helper.rb +13 -3
  31. data/spec/unit/controller_spec.rb +36 -0
  32. data/spec/unit/exposure_spec.rb +146 -0
  33. data/spec/unit/exposures_spec.rb +63 -0
  34. data/spec/unit/renderer_spec.rb +2 -1
  35. data/spec/unit/scope_spec.rb +98 -0
  36. metadata +36 -46
  37. data/lib/dry/view/layout.rb +0 -126
  38. data/lib/dry/view/null_part.rb +0 -30
  39. data/lib/dry/view/part.rb +0 -39
  40. data/lib/dry/view/value_part.rb +0 -50
  41. data/spec/unit/layout_spec.rb +0 -55
  42. data/spec/unit/null_part_spec.rb +0 -39
  43. data/spec/unit/value_part_spec.rb +0 -55
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f3b4e09263f41a0b0972c1270fa32e5911ad028b
4
- data.tar.gz: b7787ff1b20f6fae7c4c67461ac7e2c1cf51e498
3
+ metadata.gz: 5cf179c08c3deb29086bc87197420a301595a70f
4
+ data.tar.gz: 1c6eccdfb39502b559748c8c75d4c4b127b16019
5
5
  SHA512:
6
- metadata.gz: d79d4a61109cce4b3885d5c0bba544563ebd8d253465acb33c1022f62a61f369de0c972a2ea6657d1d6fb76841a4e4e5baaea7d5df16864e6f2f0b43e54ae881
7
- data.tar.gz: 84a995bd47ddd4909cc8658bb2af52dc369b96b9c37d4f74add32a8fc21ce682837fbb7226c16aab164c0389197b5d9183b3bc82009ed608c7fb2d6c9002c3dc
6
+ metadata.gz: 390c86f0b801d44bfe8a5958a982da88a52030dbfbf4403380af90c82c1279d3603a0f4376d1b2f349f3e42f36628c3a551b37e3fe8d2d75874b77d1e4d1efb3
7
+ data.tar.gz: cfdc7df2e7d8b63cda8611d203d9ec39da0a31d9237e742a00e861244556b2cfc5854b09a312abb358f77c572d4102b56d707d74ee27a61154fb7d6c44952756
data/.travis.yml CHANGED
@@ -1,25 +1,29 @@
1
1
  language: ruby
2
+ dist: trusty
2
3
  sudo: false
3
4
  cache: bundler
4
5
  bundler_args: --without tools benchmarks
6
+ before_install:
7
+ - gem update --system
8
+ - rvm @global do gem uninstall bundler -a -x
9
+ - rvm @global do gem install bundler -v 1.13.7
5
10
  script:
6
- - bundle exec rake spec
11
+ - bundle exec rake
12
+ after_success:
13
+ # Send coverage report from the job #1 == current MRI release
14
+ - '[ "${TRAVIS_JOB_NUMBER#*.}" = "1" ] && [ "$TRAVIS_BRANCH" = "master" ] && bundle exec codeclimate-test-reporter'
7
15
  rvm:
8
- - 2.0
9
- - 2.1
10
- - 2.2
11
- - 2.3.0
12
- - rbx
13
- - jruby-9000
14
- - ruby-head
15
- - jruby-head
16
+ - 2.4.0
17
+ - 2.3.3
18
+ - 2.2.6
19
+ - 2.1.10
20
+ - jruby-9.1.6.0
16
21
  env:
17
22
  global:
18
23
  - JRUBY_OPTS='--dev -J-Xmx1024M'
19
24
  matrix:
20
25
  allow_failures:
21
- - rvm: ruby-head
22
- - rvm: jruby-head
26
+ - rvm: jruby-9.1.6.0
23
27
  notifications:
24
28
  email: false
25
29
  webhooks:
data/CHANGELOG.md CHANGED
@@ -1,7 +1,30 @@
1
+ # 0.2.0 / 2017-01-30
2
+
3
+ This release is a major reorientation for dry-view, and it should allow for more natural, straightforward template authoring.
4
+
5
+ ### Changed
6
+
7
+ - [BREAKING] `Dry::View::Layout` renamed to `Dry::View::Controller`. The "view controller" name better represents this object's job: to (timriley)
8
+ - [BREAKING] `Dry::View::Controller`'s `name` setting is replaced by `template`, which also supports falsey values to disable layout rendering entirely (timriley)
9
+ - [BREAKING] `Dry::View::Controller`'s `formats` setting is replaced by `default_format`, which expects a simple string or symbol. The default value is `:html`. (timriley)
10
+ - [BREAKING] `Dry::View::Controller`'s `root` setting is replaced by `paths`, which can now accept an array of one or more directories. These will be searched for templates in order, with the first match winning (timriley)
11
+ - [BREAKING] `Dry::View::Controller`'s `scope` setting is removed and replaced by `context`, which will be made available to all templates rendered from a view controller (layouts and partials inculded), not just the layout (timriley)
12
+ - [BREAKING] View parts have been replaced by a simple `Scope`. Data passed to the templates can be accessed directly, rather than wrapped up in a view part. (timriley)
13
+ - [BREAKING] With view parts removed, partials can only be rendered by top-level method calls within templates (timriley)
14
+ - Ruby version 2.1.0 is now the earliest supported version (timriley)
15
+
16
+ ### Added
17
+
18
+ - Will render templates using any Tilt-supported engine, based on the template's final file extension (e.g. `hello.html.slim` will use Slim). For thread-safety, be sure to explicitly require any engine gems you intend to use. (timriley)
19
+ - `expose` (and `expose_private`) `Dry::View::Controller` class methods allow you to more easily declare and prepare the data for your template (timriley)
20
+ - Added `Dry::View::Scope`, which is the scope used for rendering templates. This includes the data from the exposures along with the context object (timriley)
21
+
1
22
  # 0.1.1 / 2016-07-07
2
23
 
3
24
  ### Changed
4
25
 
26
+ - Wrap `page` object exposed to layout templates in a part object, so it offers behaviour that is consistent with the part objects that template authors work with on other templates (timriley)
27
+ - Render template content first, before passing that content to the layout. This makes "content_for"-style behaviours possible, where the template stores some data that the layout can then use later (timriley)
5
28
  - Configure default template encoding to be UTF-8, fixing some issues with template rendering on deployed sites (gotar)
6
29
 
7
30
  # 0.1.0 / 2016-03-28
data/Gemfile CHANGED
@@ -2,16 +2,17 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
+ group :tools do
6
+ gem 'pry'
7
+ end
8
+
5
9
  group :test do
6
10
  gem 'byebug', platform: :mri
7
11
  gem 'rack', '>= 1.0.0', '<= 2.0.0'
8
12
  gem 'slim'
9
13
 
10
- gem 'codeclimate-test-reporter', platform: :rbx
11
- end
12
-
13
- group :tools do
14
- gem 'pry'
14
+ gem 'simplecov'
15
+ gem 'codeclimate-test-reporter'
15
16
  end
16
17
 
17
18
  group :benchmarks do
data/README.md CHANGED
@@ -12,4 +12,11 @@
12
12
  [![Test Coverage](https://img.shields.io/codeclimate/coverage/github/dry-rb/dry-view.svg)][code_climate]
13
13
  [![API Documentation Coverage](http://inch-ci.org/github/dry-rb/dry-view.svg)][inch]
14
14
 
15
- Data-oriented view rendering system.
15
+
16
+ A simple, standalone view rendering system built around functional view
17
+ controllers and templates. dry-view allows you to model your views as stateless
18
+ transformations, accepting user input and returning your rendered view.
19
+
20
+ ## Links
21
+
22
+ * [Documentation](http://dry-rb.org/gems/dry-view)
data/benchmarks/view.rb CHANGED
@@ -12,14 +12,13 @@ class ActionRender
12
12
  end
13
13
 
14
14
  action_renderer = ActionRender.new
15
- rodakase_renderer = Dry::View::Renderer.new(Pathname(__FILE__).dirname.join('templates'), engine: :erb)
16
-
17
- template = rodakase_renderer.dir.join('button.erb')
15
+ dry_view_renderer = Dry::View::Renderer.new(Pathname(__FILE__).dirname.join('templates'), format: :html)
18
16
 
17
+ template = Pathname(__FILE__).dirname.join('templates').join('button.html.erb')
19
18
  SCOPE = {}
20
19
 
21
20
  Benchmark.ips do |x|
22
21
  x.report('actionview') { action_renderer.button }
23
- x.report('rodakase') { rodakase_renderer.render(template, SCOPE) }
22
+ x.report('dry-view') { dry_view_renderer.render(template, SCOPE) }
24
23
  x.compare!
25
24
  end
data/bin/console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "dry-view"
5
+
6
+ require "pry"
7
+ Pry.start
data/dry-view.gemspec CHANGED
@@ -6,19 +6,21 @@ require 'dry/view/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "dry-view"
8
8
  spec.version = Dry::View::VERSION
9
- spec.authors = ["Piotr Solnica"]
10
- spec.email = ["piotr.solnica@gmail.com"]
11
- spec.summary = "Lightweight web application stack on top of Roda"
9
+ spec.authors = ["Piotr Solnica", "Tim Riley"]
10
+ spec.email = ["piotr.solnica@gmail.com", "tim@icelab.com.au"]
11
+ spec.summary = "Functional view rendering system"
12
12
  spec.description = spec.summary
13
13
  spec.homepage = "https://github.com/dry-rb/dry-view"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
20
  spec.require_paths = ["lib"]
20
21
 
21
- spec.add_runtime_dependency "inflecto", "~> 0"
22
+ spec.required_ruby_version = '>= 2.1.0'
23
+
22
24
  spec.add_runtime_dependency "tilt", "~> 2.0"
23
25
  spec.add_runtime_dependency "dry-configurable", "~> 0.1"
24
26
  spec.add_runtime_dependency "dry-equalizer", "~> 0.2"
@@ -26,5 +28,4 @@ Gem::Specification.new do |spec|
26
28
  spec.add_development_dependency "bundler", "~> 1.7"
27
29
  spec.add_development_dependency "rake", "~> 10.0"
28
30
  spec.add_development_dependency "rspec", "~> 3.1"
29
- spec.add_development_dependency "capybara", "~> 2.5"
30
31
  end
@@ -0,0 +1,107 @@
1
+ require 'dry-configurable'
2
+ require 'dry-equalizer'
3
+
4
+ require 'dry/view/path'
5
+ require 'dry/view/exposures'
6
+ require 'dry/view/renderer'
7
+ require 'dry/view/scope'
8
+
9
+ module Dry
10
+ module View
11
+ class Controller
12
+ DEFAULT_LAYOUTS_DIR = 'layouts'.freeze
13
+ DEFAULT_CONTEXT = Object.new.freeze
14
+ EMPTY_LOCALS = {}.freeze
15
+
16
+ include Dry::Equalizer(:config)
17
+
18
+ extend Dry::Configurable
19
+
20
+ setting :paths
21
+ setting :layout, false
22
+ setting :context, DEFAULT_CONTEXT
23
+ setting :template
24
+ setting :default_format, :html
25
+
26
+ attr_reader :config
27
+ attr_reader :layout_dir
28
+ attr_reader :layout_path
29
+ attr_reader :template_path
30
+ attr_reader :exposures
31
+
32
+ def self.paths
33
+ Array(config.paths).map { |path| Dry::View::Path.new(path) }
34
+ end
35
+
36
+ def self.renderer(format)
37
+ renderers.fetch(format) {
38
+ renderers[format] = Renderer.new(paths, format: format)
39
+ }
40
+ end
41
+
42
+ def self.renderers
43
+ @renderers ||= {}
44
+ end
45
+
46
+ def self.expose(*names, **options, &block)
47
+ if names.length == 1
48
+ exposures.add(names.first, block, **options)
49
+ else
50
+ names.each do |name|
51
+ exposures.add(name, nil, **options)
52
+ end
53
+ end
54
+ end
55
+
56
+ def self.private_expose(*names, &block)
57
+ expose(*names, to_view: false, &block)
58
+ end
59
+
60
+ def self.exposures
61
+ @exposures ||= Exposures.new
62
+ end
63
+
64
+ def initialize
65
+ @config = self.class.config
66
+ @layout_dir = DEFAULT_LAYOUTS_DIR
67
+ @layout_path = "#{layout_dir}/#{config.layout}"
68
+ @template_path = config.template
69
+ @exposures = self.class.exposures.bind(self)
70
+ end
71
+
72
+ def call(format: config.default_format, **input)
73
+ renderer = self.class.renderer(format)
74
+
75
+ template_content = renderer.(template_path, template_scope(renderer, **input))
76
+
77
+ return template_content unless layout?
78
+
79
+ renderer.(layout_path, layout_scope(renderer, **input)) do
80
+ template_content
81
+ end
82
+ end
83
+
84
+ def locals(locals: EMPTY_LOCALS, **input)
85
+ exposures.locals(input).merge(locals)
86
+ end
87
+
88
+ private
89
+
90
+ def layout?
91
+ !!config.layout
92
+ end
93
+
94
+ def layout_scope(renderer, context: config.context, **)
95
+ scope(renderer.chdir(layout_dir), EMPTY_LOCALS, context)
96
+ end
97
+
98
+ def template_scope(renderer, context: config.context, **input)
99
+ scope(renderer.chdir(template_path), locals(**input), context)
100
+ end
101
+
102
+ def scope(renderer, locals, context)
103
+ Scope.new(renderer, locals, context)
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,61 @@
1
+ module Dry
2
+ module View
3
+ class Exposure
4
+ SUPPORTED_PARAMETER_TYPES = [:req, :opt].freeze
5
+
6
+ attr_reader :name
7
+ attr_reader :proc
8
+ attr_reader :to_view
9
+
10
+ def initialize(name, proc = nil, to_view: true)
11
+ ensure_proc_parameters(proc) if proc
12
+
13
+ @name = name
14
+ @proc = proc
15
+ @to_view = to_view
16
+ end
17
+
18
+ def bind(obj)
19
+ proc ? self : with_default_proc(obj)
20
+ end
21
+
22
+ def dependencies
23
+ proc.parameters.map(&:last)
24
+ end
25
+
26
+ alias_method :to_view?, :to_view
27
+
28
+ def call(input, locals = {})
29
+ params = dependencies.map.with_index { |name, position|
30
+ if position.zero?
31
+ locals.fetch(name) { input }
32
+ else
33
+ locals.fetch(name)
34
+ end
35
+ }
36
+
37
+ proc.(*params)
38
+ end
39
+
40
+ private
41
+
42
+ def with_default_proc(obj)
43
+ self.class.new(name, build_default_proc(obj), to_view: to_view)
44
+ end
45
+
46
+ def build_default_proc(obj)
47
+ if obj.respond_to?(name, _include_private = true)
48
+ obj.method(name)
49
+ else
50
+ -> input { input.fetch(name) }
51
+ end
52
+ end
53
+
54
+ def ensure_proc_parameters(proc)
55
+ if proc.parameters.any? { |type, _| !SUPPORTED_PARAMETER_TYPES.include?(type) }
56
+ raise ArgumentError, "+proc+ must take positional arugments only"
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,50 @@
1
+ require "tsort"
2
+ require "dry/view/exposure"
3
+
4
+ module Dry
5
+ module View
6
+ class Exposures
7
+ include TSort
8
+
9
+ attr_reader :exposures
10
+
11
+ def initialize(exposures = {})
12
+ @exposures = exposures
13
+ end
14
+
15
+ def [](name)
16
+ exposures[name]
17
+ end
18
+
19
+ def add(name, proc = nil, **options)
20
+ exposures[name] = Exposure.new(name, proc, **options)
21
+ end
22
+
23
+ def bind(obj)
24
+ bound_exposures = Hash[exposures.map { |name, exposure|
25
+ [name, exposure.bind(obj)]
26
+ }]
27
+
28
+ self.class.new(bound_exposures)
29
+ end
30
+
31
+ def locals(input)
32
+ tsort.each_with_object({}) { |name, memo|
33
+ memo[name] = self[name].(input, memo) if exposures.key?(name)
34
+ }.each_with_object({}) { |(name, val), memo|
35
+ memo[name] = val if self[name].to_view?
36
+ }
37
+ end
38
+
39
+ private
40
+
41
+ def tsort_each_node(&block)
42
+ exposures.each_key(&block)
43
+ end
44
+
45
+ def tsort_each_child(name, &block)
46
+ self[name].dependencies.each(&block) if exposures.key?(name)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,40 @@
1
+ require "pathname"
2
+
3
+ module Dry
4
+ module View
5
+ class Path
6
+ include Dry::Equalizer(:dir, :root)
7
+
8
+ attr_reader :dir, :root
9
+
10
+ def initialize(dir, options = {})
11
+ @dir = Pathname(dir)
12
+ @root = Pathname(options.fetch(:root, dir))
13
+ end
14
+
15
+ def lookup(name, format)
16
+ template?(name, format) || template?("shared/#{name}", format) || !root? && chdir('..').lookup(name, format)
17
+ end
18
+
19
+ def chdir(dirname)
20
+ self.class.new(dir.join(dirname), root: root)
21
+ end
22
+
23
+ def to_s
24
+ dir
25
+ end
26
+
27
+ private
28
+
29
+ def root?
30
+ dir == root
31
+ end
32
+
33
+ # Search for a template using a wildcard for the engine extension
34
+ def template?(name, format)
35
+ glob = dir.join("#{name}.#{format}.*")
36
+ Dir[glob].first
37
+ end
38
+ end
39
+ end
40
+ end
@@ -4,21 +4,19 @@ require 'dry-equalizer'
4
4
  module Dry
5
5
  module View
6
6
  class Renderer
7
- include Dry::Equalizer(:dir, :root, :engine)
7
+ include Dry::Equalizer(:paths, :format)
8
8
 
9
9
  TemplateNotFoundError = Class.new(StandardError)
10
10
 
11
- attr_reader :dir, :root, :format, :engine, :tilts
11
+ attr_reader :paths, :format, :engine, :tilts
12
12
 
13
13
  def self.tilts
14
14
  @__engines__ ||= {}
15
15
  end
16
16
 
17
- def initialize(dir, options = {})
18
- @dir = dir
19
- @root = options.fetch(:root, dir)
20
- @format = options[:format]
21
- @engine = options[:engine]
17
+ def initialize(paths, format:)
18
+ @paths = paths
19
+ @format = format
22
20
  @tilts = self.class.tilts
23
21
  end
24
22
 
@@ -28,7 +26,8 @@ module Dry
28
26
  if path
29
27
  render(path, scope, &block)
30
28
  else
31
- raise TemplateNotFoundError, "Template #{template} could not be looked up within #{root}"
29
+ msg = "Template #{template.inspect} could not be found in paths:\n#{paths.map { |pa| "- #{pa.to_s}" }.join("\n")}"
30
+ raise TemplateNotFoundError, msg
32
31
  end
33
32
  end
34
33
 
@@ -36,32 +35,25 @@ module Dry
36
35
  tilt(path).render(scope, &block)
37
36
  end
38
37
 
39
- def tilt(path)
40
- tilts.fetch(path) { tilts[path] = Tilt[engine].new(path, nil, default_encoding: "utf-8") }
41
- end
42
-
43
- def lookup(name)
44
- template?(name) || template?("shared/#{name}") || !root? && chdir('..').lookup(name)
45
- end
38
+ def chdir(dirname)
39
+ new_paths = paths.map { |path| path.chdir(dirname) }
46
40
 
47
- def root?
48
- dir == root
41
+ self.class.new(new_paths, format: format)
49
42
  end
50
43
 
51
- def template?(name)
52
- template_path = path(name)
53
-
54
- if File.exist?(template_path)
55
- template_path
56
- end
44
+ def lookup(name)
45
+ paths.inject(false) { |result, path|
46
+ result || path.lookup(name, format)
47
+ }
57
48
  end
58
49
 
59
- def path(name)
60
- dir.join("#{name}.#{format}.#{engine}")
61
- end
50
+ private
62
51
 
63
- def chdir(dirname)
64
- self.class.new(dir.join(dirname), engine: engine, format: format, root: root)
52
+ # TODO: make default_encoding configurable
53
+ def tilt(path)
54
+ tilts.fetch(path) {
55
+ tilts[path] = Tilt.new(path, nil, default_encoding: "utf-8")
56
+ }
65
57
  end
66
58
  end
67
59
  end
@@ -0,0 +1,55 @@
1
+ require 'dry-equalizer'
2
+
3
+ module Dry
4
+ module View
5
+ class Scope
6
+ include Dry::Equalizer(:_renderer, :_data)
7
+
8
+ attr_reader :_renderer
9
+ attr_reader :_data
10
+ attr_reader :_context
11
+
12
+ def initialize(renderer, data, context = nil)
13
+ @_renderer = renderer
14
+ @_data = data.to_hash
15
+ @_context = context
16
+ end
17
+
18
+ def respond_to_missing?(name, include_private = false)
19
+ _template?(name) || _data.key?(name) || _context.respond_to?(name)
20
+ end
21
+
22
+ private
23
+
24
+ def method_missing(name, *args, &block)
25
+ if _data.key?(name)
26
+ _data[name]
27
+ elsif _context.respond_to?(name)
28
+ _context.public_send(name, *args, &block)
29
+ elsif (template_path = _template?(name))
30
+ _render(template_path, *args, &block)
31
+ else
32
+ super
33
+ end
34
+ end
35
+
36
+ def _template?(name)
37
+ _renderer.lookup("_#{name}")
38
+ end
39
+
40
+ def _render(path, *args, &block)
41
+ _renderer.render(path, _render_args(*args), &block)
42
+ end
43
+
44
+ def _render_args(*args)
45
+ if args.empty?
46
+ self
47
+ elsif args.length == 1 && args.first.respond_to?(:to_hash)
48
+ self.class.new(_renderer, args.first, _context)
49
+ else
50
+ raise ArgumentError, "render argument must be a Hash"
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  module View
3
- VERSION = '0.1.1'.freeze
3
+ VERSION = '0.2.0'.freeze
4
4
  end
5
5
  end
data/lib/dry/view.rb CHANGED
@@ -1,2 +1,2 @@
1
1
  require 'dry/view/renderer'
2
- require 'dry/view/layout'
2
+ require 'dry/view/controller'
@@ -0,0 +1 @@
1
+ p This is a view with no locals.
@@ -1,6 +1,6 @@
1
1
  doctype html
2
2
  html
3
3
  head
4
- title == page.title
4
+ title == title
5
5
  body
6
6
  == yield
@@ -1,3 +1,3 @@
1
- # <%= page.title %>
1
+ # <%= title %>
2
2
 
3
3
  <%= yield %>
@@ -0,0 +1,3 @@
1
+ div.box
2
+ h2 = label
3
+ = user[:name]
@@ -0,0 +1,3 @@
1
+ .users
2
+ - users.each do |user|
3
+ == box user: user, label: "Nombre"
@@ -1,5 +1,5 @@
1
1
  tbody
2
2
  - users.each do |user|
3
- == user.row do
3
+ == row do
4
4
  td = user[:name]
5
5
  td = user[:email]
@@ -1,5 +1,5 @@
1
- h2 = subtitle
2
-
3
1
  .users
4
- == users.index_table do
5
- == users.tbody
2
+ == index_table do
3
+ == tbody
4
+
5
+ img src=assets["mindblown"]
@@ -1,5 +1,3 @@
1
- ## <%= subtitle %>
2
-
3
1
  <% users.each do |user| %>
4
2
  * <%= user[:name] %> (<%= user[:email] %>)
5
3
  <% end %>
@@ -0,0 +1,5 @@
1
+ ul
2
+ - users.each do |user|
3
+ li = "#{user[:name]} (#{user[:email]})"
4
+
5
+ .count = users_count
@@ -0,0 +1,5 @@
1
+ h1 OVERRIDE
2
+
3
+ .users
4
+ == index_table do
5
+ == tbody