render_me_pretty 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0ca366dbc0b626c3bd1fa15b7d83f8d29ab4b22a0eabd35dc6d1c68604b0925
4
- data.tar.gz: 18a6fbec659aa7d6fde4053277aa10d5836d7703d38e2b9b29e78399a921b264
3
+ metadata.gz: 5fca5bd4ed5c7502ec8b72669e5fced039e90b8e4f1cdb6f47fdaab6f289e247
4
+ data.tar.gz: 26ecbd9090b108e5baf921cec068a06a2ac4057232d984792304e49d0d038304
5
5
  SHA512:
6
- metadata.gz: 71a16eef148da71913f34478c8981915f8844e4586344771fd490d21f61c7f5cbd3a22d83f5b61deedad188f04b696372cca8b8185687ab9e44e058751554a36
7
- data.tar.gz: 6e68c1e4fa8c5d1fd0e133b1e4d0ec44d708deaccd888b5ba23fadd49cec30d74b1918b6d48de921be49face3ed28013309d0bfac6695515f10dcb40904743a6
6
+ metadata.gz: bb38911b2da29bc35e67d648d7de31b17b74cdfd0b7a3b97bfbb6419a641d884c77d063d84ba9f4abd195f2fc6ebf7915e598b3b9b2b6ff18297e2cd6a6f601b
7
+ data.tar.gz: 74a63b170fcab819827e3f808f0b14c25925b162c123b9b7f519c39b2b77e07a858fe38c351fa3e08cfbc4ce6a52c5c70dc3a687f069993bc6348e8179ca253c
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project *tries* to adhere to [Semantic Versioning](http://semver.org/), even before v1.0.
5
5
 
6
+ ## [0.4.0]
7
+ - fix erb and context definitions, fix bug with empty variables={}
8
+ - improve original backtrace info, colorize exact line
9
+
10
+ ## [0.3.0]
11
+ - fix bug with empty variables={}
12
+ - fix erb and context definitions
13
+
6
14
  ## [0.2.0]
7
15
  - add RenderMePretty.result convenience class method
8
16
 
@@ -1,14 +1,15 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- render_me_pretty (0.1.0)
4
+ render_me_pretty (0.3.0)
5
5
  activesupport
6
6
  colorize
7
+ tilt
7
8
 
8
9
  GEM
9
10
  remote: https://rubygems.org/
10
11
  specs:
11
- activesupport (5.1.4)
12
+ activesupport (5.1.5)
12
13
  concurrent-ruby (~> 1.0, >= 1.0.2)
13
14
  i18n (~> 0.7)
14
15
  minitest (~> 5.1)
@@ -16,7 +17,7 @@ GEM
16
17
  colorize (0.8.1)
17
18
  concurrent-ruby (1.0.5)
18
19
  diff-lcs (1.3)
19
- i18n (0.9.4)
20
+ i18n (0.9.5)
20
21
  concurrent-ruby (~> 1.0)
21
22
  minitest (5.11.3)
22
23
  rake (12.3.0)
@@ -34,6 +35,7 @@ GEM
34
35
  rspec-support (~> 3.7.0)
35
36
  rspec-support (3.7.1)
36
37
  thread_safe (0.3.6)
38
+ tilt (2.0.8)
37
39
  tzinfo (1.2.5)
38
40
  thread_safe (~> 0.1)
39
41
 
data/README.md CHANGED
@@ -45,6 +45,26 @@ There's also a convenience class method:
45
45
  RenderMePretty.result("/path/to/tempate.erb", a: 5)
46
46
  ```
47
47
 
48
+ ### Custom Context
49
+
50
+ ```ruby
51
+ person = Person.new("tung")
52
+ erb = RenderMePretty::Erb.new("/path/to/tempate.erb", a: 3, context: person) } # passing context here
53
+ erb.render(a: 4)
54
+
55
+ person = Person.new("tung")
56
+ erb = RenderMePretty::Erb.new("/path/to/tempate.erb", a: 3) }
57
+ erb.render(person, a: 4) # passing context here
58
+ ```
59
+
60
+ The context's methods and instance variables are available in the ERB template. Variables passed at initialization time to `RenderMePretty::Erb.new` or at call time for `render` be set as instance variables to a clone of the original context object.
61
+
62
+ So in the case above, if there was an `@a` instance variable in the Person object, it will not get respected. Instead the value would be `@a = 4`.
63
+
64
+ ### Context
65
+
66
+ You can pass in a context object also. Examples:
67
+
48
68
  A few more examples are in the [erb_spec.rb](spec/lib/render_me_pretty/erb_spec.rb)
49
69
 
50
70
  ## Installation
@@ -1,11 +1,12 @@
1
1
  require "render_me_pretty/version"
2
+ require "active_support/core_ext/string"
3
+ require "colorize"
2
4
 
3
5
  module RenderMePretty
4
6
  autoload :Erb, 'render_me_pretty/erb'
5
- autoload :Context, 'render_me_pretty/context'
6
7
 
7
- def self.result(path, variables={})
8
- erb = Erb.new(path, variables={})
8
+ def result(path, variables={})
9
+ erb = Erb.new(path, variables)
9
10
  erb.render
10
11
  end
11
12
 
@@ -1,30 +1,154 @@
1
+ =begin
2
+ ## Usage examples:
3
+
4
+ Given an example template /path/to/template.erb that contains:
5
+
6
+ a: <%= @a %>
7
+
8
+ ### Variables at initialization
9
+
10
+ erb = RenderMePretty::Erb.new("/path/to/template.erb", a: 1)
11
+ erb.render
12
+
13
+ Result: a: 1
14
+
15
+ ### Variables at render time
16
+
17
+ erb = RenderMePretty::Erb.new("/path/to/template.erb")
18
+ erb.render(a: 2)
19
+
20
+ Result: a: 2
21
+
22
+ ### Variables at both initialization and render time:
23
+
24
+ erb = RenderMePretty::Erb.new("/path/to/template.erb", a: 3)
25
+ erb.render(a: "override", a: 4)
26
+
27
+ Result: a: 4
28
+
29
+ Variables at render time will override variables at initialization time.
30
+
31
+ ## Context Scope
32
+
33
+ If you want to use your own context object, pass it as a variable. The context variable is specially treated as a context object. Example:
34
+
35
+ person = Person.new # must implement get_binding
36
+ erb = RenderMePretty::Erb.new("/path/to/template.erb")
37
+ erb.render(context: person, a: 2)
38
+
39
+ The context will be `person`. So person methods and instance variables will be available in the ERB templates.
40
+
41
+ =end
42
+ require 'tilt/erb'
43
+
1
44
  module RenderMePretty
2
- class Context
3
- def initialize(hash={})
4
- # http://stackoverflow.com/questions/1338960/ruby-templates-how-to-pass-variables-into-inlined-erb
5
- hash.each do |key, value|
6
- instance_variable_set('@' + key.to_s, value)
7
- end
45
+ class Erb
46
+ def initialize(path, variables={})
47
+ @path = path
48
+ @init_vars = variables
49
+ @context = variables.delete(:context)
8
50
  end
9
51
 
10
- def override_variables!(vars)
11
- vars.each do |key, value|
12
- instance_variable_set('@' + key.to_s, value)
52
+ # Usage:
53
+ #
54
+ # render(context, a: 1, b: 2)
55
+ # render(a: 1, b: 2)
56
+ # render
57
+ def render(*args)
58
+ if args.last.is_a?(Hash)
59
+ render_vars = args.pop
60
+ @init_vars = @init_vars.merge(render_vars)
61
+ end
62
+ context = args[0]
63
+ context ||= @context || Object.new
64
+
65
+ context = context.clone # so we dont stomp the original object
66
+ # override context's instance variables with init and render vars.
67
+ @init_vars.each do |key, value|
68
+ context.instance_variable_set('@' + key.to_s, value)
69
+ end
70
+
71
+ template = Tilt::ERBTemplate.new(@path)
72
+ begin
73
+ template.render(context)
74
+ rescue Exception => e
75
+ handle_exception(e)
13
76
  end
14
77
  end
15
78
 
16
- def get_binding
17
- binding
79
+ # handles Tilt error
80
+ def handle_exception(e)
81
+ # first line of the baacktrace for Tilt has the line number
82
+ # spec/fixtures/invalid.erb:2:in `block in singleton class'
83
+ error_info = e.backtrace[0]
84
+ error_line_number = error_info.split(':')[1].to_i
85
+ pretty_error(e, error_line_number)
18
86
  end
19
87
 
20
- def self.load_helpers(base_folder)
21
- Dir.glob("#{base_folder}/**/*_helper.rb").each do |path|
22
- relative_path = path.sub("#{base_folder}/", "")
23
- class_name = File.basename(relative_path, '.rb').classify
88
+ def pretty_error(e, line)
89
+ pretty_path = @path.sub(/^\.\//, '')
90
+ io = StringIO.new
91
+ io.puts "#{e.class}: #{e.message}"
92
+ io.puts "Error evaluating ERB template on line #{line.to_s.colorize(:red)} of: #{pretty_path}:"
24
93
 
25
- require path
26
- include const_get(class_name)
94
+ template = IO.read(@path)
95
+ template_lines = template.split("\n")
96
+ context = 5 # lines of context
97
+ top, bottom = [line-context-1, 0].max, line+context-1
98
+ spacing = template_lines.size.to_s.size
99
+ template_lines[top..bottom].each_with_index do |line_content, index|
100
+ line_number = top+index+1
101
+ if line_number == line
102
+ io.printf("%#{spacing}d %s\n".colorize(:red), line_number, line_content)
103
+ else
104
+ io.printf("%#{spacing}d %s\n", line_number, line_content)
105
+ end
27
106
  end
107
+
108
+ io.puts backtrace_lines(e)
109
+
110
+ if ENV['TEST']
111
+ io.string
112
+ else
113
+ puts io.string
114
+ exit 1
115
+ end
116
+ end
117
+
118
+ # Method produces a filtered original stack trace that can be appended to
119
+ # the pretty backtrace output.
120
+ #
121
+ # It parses the original backtrace that looks something like this:
122
+ #
123
+ # (erb):380:in `get_binding'
124
+ # /Users/tung/.rbenv/versions/2.5.0/lib/ruby/2.5.0/erb.rb:885:in `eval'
125
+ # /Users/tung/.rbenv/versions/2.5.0/lib/ruby/2.5.0/erb.rb:885:in `result'
126
+ # /Users/tung/src/tongueroo/lono/vendor/render_me_pretty/lib/render_me_pretty/erb.rb:67:in `render'
127
+ # /Users/tung/src/tongueroo/lono/vendor/render_me_pretty/lib/render_me_pretty.rb:11:in `result'
128
+ # /Users/tung/src/tongueroo/lono/lib/lono/template/template.rb:32:in `build'
129
+ # /Users/tung/src/tongueroo/lono/lib/lono/template/dsl.rb:82:in `block in build_templates'
130
+ # /Users/tung/src/tongueroo/lono/lib/lono/template/dsl.rb:81:in `each'
131
+ def backtrace_lines(e)
132
+ full = ENV['FULL_BACKTRACE']
133
+ if full
134
+ lines = e.backtrace
135
+ else
136
+ lines = e.backtrace
137
+ # filter out internal lines
138
+ removal_index = lines.find_index { |l| l =~ %r[lib/render_me_pretty] }
139
+ lines = lines[removal_index..-1] # remove leading lines above the lib/
140
+ # render_me_pretty lines by keeping lines past the removal index
141
+ lines.reject! { |l| l =~ %r[lib/render_me_pretty] } # now filter out
142
+ # render_me_pretty lines
143
+ lines = lines[0..7] # keep 8 lines
144
+ lines[0] = lines[0].colorize(:red)
145
+ end
146
+
147
+ # header
148
+ lines.unshift "\nOriginal filtered backtrace#{full ? '' : ' (last 8 lines)'}:"
149
+ # footer
150
+ lines << "\nRe-run with FULL_STACK_TRACE=1 to see all lines"
151
+ lines.join("\n")
28
152
  end
29
153
  end
30
154
  end
@@ -1,3 +1,3 @@
1
1
  module RenderMePretty
2
- VERSION = "0.2.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_dependency "activesupport"
22
22
  spec.add_dependency "colorize"
23
+ spec.add_dependency "tilt"
23
24
 
24
25
  spec.add_development_dependency "bundler"
25
26
  spec.add_development_dependency "rake"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: render_me_pretty
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tung Nguyen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-02-13 00:00:00.000000000 Z
11
+ date: 2018-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: tilt
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -97,7 +111,6 @@ files:
97
111
  - bin/console
98
112
  - bin/setup
99
113
  - lib/render_me_pretty.rb
100
- - lib/render_me_pretty/context.rb
101
114
  - lib/render_me_pretty/erb.rb
102
115
  - lib/render_me_pretty/version.rb
103
116
  - render_me_pretty.gemspec
@@ -1,115 +0,0 @@
1
- require "active_support/core_ext/string"
2
- require "colorize"
3
-
4
- =begin
5
- ## Usage examples:
6
-
7
- Given an example template /path/to/template.erb that contains:
8
-
9
- a: <%= @a %>
10
-
11
- ### Variables at initialization
12
-
13
- erb = RenderMePretty::Erb.new("/path/to/template.erb", a: 1)
14
- erb.render
15
-
16
- Result: a: 1
17
-
18
- ### Variables at render time
19
-
20
- erb = RenderMePretty::Erb.new("/path/to/template.erb")
21
- erb.render(a: 2)
22
-
23
- Result: a: 2
24
-
25
- ### Variables at both initialization and render time:
26
-
27
- erb = RenderMePretty::Erb.new("/path/to/template.erb", a: 3)
28
- erb.render(a: "override", a: 4)
29
-
30
- Result: a: 4
31
-
32
- Variables at render time will override variables at initialization time.
33
-
34
- ## Context Helpers
35
-
36
- When no context is provided, a built-in context object is created. You can add helpers to the built-in context object with:
37
-
38
- RenderMePretty::Context.load_helpers("lib/helpers")
39
-
40
- This loads modules defined in `lib/helpers` folder and adds their methods of the built-in context object. The helper classes must be defined with the following convetion: FooHelper and foo_helper.rb.
41
-
42
- Note, helpers will only work with the built-in context scope. If you are passing in your own context object to be used, then you should handle adding helper methods to that context object yourself.
43
-
44
- ## Custom Context Scope
45
-
46
- A built-in context object is provided for convenience. If you want to use your own context object, pass it as a variable. The context variable is specially treated as a context object. Example:
47
-
48
- person = Person.new # must implement get_binding
49
- erb = RenderMePretty::Erb.new("/path/to/template.erb")
50
- erb.render(context: person, a: 2)
51
-
52
- The context will be `person`. So person methods and instance variables will be available in the ERB templates.
53
-
54
- =end
55
- module RenderMePretty
56
- class Erb
57
- def initialize(path, variables={})
58
- @path = path
59
- @variables = variables
60
- if variables[:context]
61
- @context = variables.delete(:context)
62
- else
63
- @context = Context.new(variables)
64
- end
65
- end
66
-
67
- def render(override_vars={})
68
- @context.override_variables!(override_vars)
69
- template = IO.read(@path)
70
- ERB.new(template, nil, "-").result(@context.get_binding)
71
- rescue Exception => e
72
- handle_exception(e)
73
- end
74
-
75
- # How to know where ERB stopped? - https://www.ruby-forum.com/topic/182051
76
- # syntax errors have the (erb):xxx info in e.message
77
- # undefined variables have (erb):xxx info in e.backtrace
78
- def handle_exception(e)
79
- error_info = e.message.split("\n").grep(/\(erb\)/)[0]
80
- error_info ||= e.backtrace.grep(/\(erb\)/)[0]
81
- raise unless error_info # unable to find the (erb):xxx: error line
82
-
83
- line = error_info.split(':')[1].to_i
84
- io = StringIO.new
85
- io.puts "#{e.class} evaluating ERB template on line #{line.to_s.colorize(:red)} of: #{@path.sub(/^\.\//, '')}"
86
-
87
- template = IO.read(@path)
88
- template_lines = template.split("\n")
89
- context = 5 # lines of context
90
- top, bottom = [line-context-1, 0].max, line+context-1
91
- spacing = template_lines.size.to_s.size
92
- template_lines[top..bottom].each_with_index do |line_content, index|
93
- line_number = top+index+1
94
- if line_number == line
95
- io.printf("%#{spacing}d %s\n".colorize(:red), line_number, line_content)
96
- else
97
- io.printf("%#{spacing}d %s\n", line_number, line_content)
98
- end
99
- end
100
-
101
- # Append the original stack trace also
102
- io.puts("\nOriginal backtrace (last 5 lines):")
103
- lines = ENV['FULL_STACK_TRACE'] ? e.backtrace : e.backtrace[0..4]
104
- io.write(lines.join("\n"))
105
- io.puts("\nRe-run with FULL_STACK_TRACE=1 to see all lines")
106
-
107
- if ENV['TEST']
108
- io.string
109
- else
110
- puts io.string
111
- exit 1
112
- end
113
- end
114
- end
115
- end