padrino-core 0.10.7 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/lib/padrino-core.rb +58 -4
  3. data/lib/padrino-core/application.rb +38 -16
  4. data/lib/padrino-core/application/flash.rb +229 -0
  5. data/lib/padrino-core/application/rendering.rb +39 -11
  6. data/lib/padrino-core/application/rendering/extensions/erubis.rb +55 -0
  7. data/lib/padrino-core/application/rendering/extensions/haml.rb +26 -0
  8. data/lib/padrino-core/application/rendering/extensions/slim.rb +14 -0
  9. data/lib/padrino-core/application/routing.rb +106 -35
  10. data/lib/padrino-core/cli/base.rb +41 -38
  11. data/lib/padrino-core/cli/rake.rb +30 -9
  12. data/lib/padrino-core/cli/rake_tasks.rb +9 -14
  13. data/lib/padrino-core/loader.rb +23 -9
  14. data/lib/padrino-core/locale/fr.yml +1 -1
  15. data/lib/padrino-core/locale/ru.yml +1 -1
  16. data/lib/padrino-core/logger.rb +48 -32
  17. data/lib/padrino-core/module.rb +58 -0
  18. data/lib/padrino-core/mounter.rb +15 -5
  19. data/lib/padrino-core/reloader.rb +14 -12
  20. data/lib/padrino-core/server.rb +4 -4
  21. data/lib/padrino-core/support_lite.rb +43 -6
  22. data/lib/padrino-core/version.rb +1 -1
  23. data/padrino-core.gemspec +9 -4
  24. data/test/fixtures/app_gem/Gemfile +4 -0
  25. data/test/fixtures/app_gem/app/app.rb +3 -0
  26. data/test/fixtures/app_gem/app_gem.gemspec +17 -0
  27. data/test/fixtures/app_gem/lib/app_gem.rb +7 -0
  28. data/test/fixtures/app_gem/lib/app_gem/version.rb +3 -0
  29. data/test/mini_shoulda.rb +1 -1
  30. data/test/test_application.rb +38 -21
  31. data/test/test_csrf_protection.rb +80 -0
  32. data/test/test_filters.rb +70 -0
  33. data/test/test_flash.rb +168 -0
  34. data/test/test_logger.rb +27 -0
  35. data/test/test_mounter.rb +24 -2
  36. data/test/test_reloader_simple.rb +4 -4
  37. data/test/test_rendering.rb +75 -4
  38. data/test/test_routing.rb +164 -35
  39. data/test/test_support_lite.rb +56 -0
  40. metadata +52 -29
@@ -0,0 +1,55 @@
1
+ begin
2
+ require 'erubis'
3
+
4
+ module Padrino
5
+ module Erubis
6
+ ##
7
+ # SafeBufferEnhancer is an Erubis Enhancer that compiles templates that
8
+ # are fit for using ActiveSupport::SafeBuffer as a Buffer.
9
+ #
10
+ # @api private
11
+ module SafeBufferEnhancer
12
+ def add_expr_literal(src, code)
13
+ src << " #{@bufvar}.concat((" << code << ').to_s);'
14
+ end
15
+
16
+ def add_expr_escaped(src, code)
17
+ src << " #{@bufvar}.safe_concat " << code << ';'
18
+ end
19
+
20
+ def add_text(src, text)
21
+ src << " #{@bufvar}.safe_concat '" << escape_text(text) << "';" unless text.empty?
22
+ end
23
+ end
24
+
25
+ ##
26
+ # SafeBufferTemplate is the classic Erubis template, augmented with
27
+ # SafeBufferEnhancer.
28
+ #
29
+ # @api private
30
+ class SafeBufferTemplate < ::Erubis::Eruby
31
+ include SafeBufferEnhancer
32
+ end
33
+
34
+ ##
35
+ # Modded ErubisTemplate that doesn't insist in an String as output
36
+ # buffer.
37
+ #
38
+ # @api private
39
+ class Template < Tilt::ErubisTemplate
40
+ def precompiled_preamble(locals)
41
+ old_postamble = super.split("\n")[0..-2]
42
+ [old_postamble, "#{@outvar} = _buf = (#{@outvar} || ActiveSupport::SafeBuffer.new)"].join("\n")
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ Tilt.prefer Padrino::Erubis::Template, :erb
49
+
50
+ if defined? Padrino::Rendering
51
+ Padrino::Rendering.engine_configurations[:erb] =
52
+ {:engine_class => Padrino::Erubis::SafeBufferTemplate}
53
+ end
54
+ rescue LoadError
55
+ end
@@ -0,0 +1,26 @@
1
+ begin
2
+ require 'haml'
3
+ require 'haml/helpers/xss_mods'
4
+
5
+ module Haml
6
+ module Helpers
7
+ include XssMods
8
+ end
9
+
10
+ module Util
11
+ def self.rails_xss_safe?
12
+ true
13
+ end
14
+ end
15
+ end
16
+
17
+ if defined? Padrino::Rendering
18
+ Padrino::Rendering.engine_configurations[:haml] =
19
+ {:escape_html => true}
20
+
21
+ class Tilt::HamlTemplate
22
+ include Padrino::Rendering::SafeTemplate
23
+ end
24
+ end
25
+ rescue LoadError
26
+ end
@@ -0,0 +1,14 @@
1
+ begin
2
+ require 'slim'
3
+
4
+ if defined? Padrino::Rendering
5
+ Padrino::Rendering.engine_configurations[:slim] =
6
+ {:generator => Temple::Generators::RailsOutputBuffer,
7
+ :buffer => "@_out_buf", :use_html_safe => true}
8
+
9
+ class Slim::Template
10
+ include Padrino::Rendering::SafeTemplate
11
+ end
12
+ end
13
+ rescue LoadError
14
+ end
@@ -11,6 +11,9 @@ class Sinatra::Request
11
11
  def controller
12
12
  route_obj && route_obj.controller
13
13
  end
14
+ def action
15
+ route_obj && route_obj.action
16
+ end
14
17
  end
15
18
 
16
19
  ##
@@ -28,8 +31,8 @@ class HttpRouter
28
31
  @route = path.route
29
32
  @params ||= {}
30
33
  @params.update(env['router.params'])
31
- @block_params = if path.route.is_a?(HttpRouter::RegexRoute)
32
- params_list = env['router.request'].extra_env['router.regex_match'].to_a
34
+ @block_params = if match_data = env['router.request'].extra_env['router.regex_match']
35
+ params_list = match_data.to_a
33
36
  params_list.shift
34
37
  @params[:captures] = params_list
35
38
  params_list
@@ -47,7 +50,6 @@ class HttpRouter
47
50
  (@route.before_filters - settings.filters[:before]).each { |block| instance_eval(&block) }
48
51
  @layout = path.route.use_layout if path.route.use_layout
49
52
  @route.custom_conditions.each { |block| pass if block.bind(self).call == false } if @route.custom_conditions
50
- @block_params = @block_params[0, @route.dest.arity] if @route.dest.arity > 0
51
53
  halt_response = catch(:halt) { route_eval { @route.dest[self, @block_params] } }
52
54
  @_response_buffer = halt_response.is_a?(Array) ? halt_response.last : halt_response
53
55
  successful = true
@@ -62,7 +64,7 @@ class HttpRouter
62
64
 
63
65
  # @private
64
66
  class Route
65
- attr_accessor :use_layout, :controller, :cache, :cache_key, :cache_expires_in
67
+ attr_accessor :use_layout, :controller, :action, :cache, :cache_key, :cache_expires_in, :parent
66
68
 
67
69
  def before_filters(&block)
68
70
  @_before_filters ||= []
@@ -84,6 +86,40 @@ class HttpRouter
84
86
 
85
87
  @_custom_conditions
86
88
  end
89
+
90
+ def significant_variable_names
91
+ @significant_variable_names ||= @original_path.nil? ? [] : @original_path.scan(/(^|[^\\])[:\*]([a-zA-Z0-9_]+)/).map{|p| p.last.to_sym}
92
+ end
93
+ end
94
+
95
+ class Node::Path
96
+ def to_code
97
+ path_ivar = inject_root_ivar(self)
98
+ "#{"if !callback && request.path.size == 1 && request.path.first == '' && (request.rack_request.head? || request.rack_request.get?) && request.rack_request.path_info[-1] == ?/
99
+ catch(:pass) do
100
+ response = ::Rack::Response.new
101
+ response.redirect(request.rack_request.path_info[0, request.rack_request.path_info.size - 1], 302)
102
+ return response.finish
103
+ end
104
+ end" if router.redirect_trailing_slash?}
105
+
106
+ #{"if request.#{router.ignore_trailing_slash? ? 'path_finished?' : 'path.empty?'}" unless route.match_partially}
107
+ catch(:pass) do
108
+ if callback
109
+ request.called = true
110
+ callback.call(Response.new(request, #{path_ivar}))
111
+ else
112
+ env = request.rack_request.dup.env
113
+ env['router.request'] = request
114
+ env['router.params'] ||= {}
115
+ #{"env['router.params'].merge!(Hash[#{param_names.inspect}.zip(request.params)])" if dynamic?}
116
+ @router.rewrite#{"_partial" if route.match_partially}_path_info(env, request)
117
+ response = @router.process_destination_path(#{path_ivar}, env)
118
+ return response unless router.pass_on_response(response)
119
+ end
120
+ end
121
+ #{"end" unless route.match_partially}"
122
+ end
87
123
  end
88
124
  end
89
125
 
@@ -98,7 +134,7 @@ module Padrino
98
134
  def apply?(request)
99
135
  detect = @args.any? do |arg|
100
136
  case arg
101
- when Symbol then request.route_obj && (request.route_obj.named == arg or request.route_obj.named == [@scoped_controller, arg].flatten.join("_").to_sym)
137
+ when Symbol then request.route_obj && (request.route_obj.name == arg or request.route_obj.name == [@scoped_controller, arg].flatten.join("_").to_sym)
102
138
  else arg === request.path_info
103
139
  end
104
140
  end || @options.any? do |name, val|
@@ -166,7 +202,7 @@ module Padrino
166
202
  # Class methods responsible for enhanced routing for controllers.
167
203
  module ClassMethods
168
204
  ##
169
- # Method for organize in a better way our routes.
205
+ # Method to organize our routes in a better way.
170
206
  #
171
207
  # @param [Array] args
172
208
  # Controller arguments.
@@ -237,8 +273,8 @@ module Padrino
237
273
  # get :index, :map => "/:lang" do; "params[:lang] == :de"; end
238
274
  # end
239
275
  #
240
- # In a controller before and after filters are scoped and didn't affect other controllers or main app.
241
- # In a controller layout are scoped and didn't affect others controllers and main app.
276
+ # In a controller, before and after filters are scoped and don't affect other controllers or the main app.
277
+ # In a controller, layouts are scoped and don't affect other controllers or the main app.
242
278
  #
243
279
  # @example
244
280
  # controller :posts do
@@ -449,7 +485,8 @@ module Padrino
449
485
  #
450
486
  def recognize_path(path)
451
487
  responses = @router.recognize(Rack::MockRequest.env_for(path))
452
- [responses[0].path.route.named, responses[0].params]
488
+ responses = responses[0] if responses[0].is_a?(Array)
489
+ [responses[0].path.route.name, responses[0].params]
453
490
  end
454
491
 
455
492
  ##
@@ -470,11 +507,12 @@ module Padrino
470
507
  params[:format] = params[:format].to_s unless params[:format].nil?
471
508
  params = value_to_param(params)
472
509
  end
473
- url = if params_array.empty?
474
- compiled_router.url(name, params)
475
- else
476
- compiled_router.url(name, *(params_array << params))
477
- end
510
+ url =
511
+ if params_array.empty?
512
+ compiled_router.path(name, params)
513
+ else
514
+ compiled_router.path(name, *(params_array << params))
515
+ end
478
516
  url[0,0] = conform_uri(uri_root) if defined?(uri_root)
479
517
  url[0,0] = conform_uri(ENV['RACK_BASE_URI']) if ENV['RACK_BASE_URI']
480
518
  url = "/" if url.blank?
@@ -556,8 +594,17 @@ module Padrino
556
594
  # Do padrino parsing. We dup options so we can build HEAD request correctly
557
595
  route_options = options.dup
558
596
  route_options[:provides] = @_provides if @_provides
597
+
598
+ # CSRF protection is always active except when explicitly switched off
599
+ if allow_disabled_csrf
600
+ unless route_options[:csrf_protection] == false
601
+ route_options[:csrf_protection] = true
602
+ end
603
+ end
604
+
559
605
  path, *route_options[:with] = path if path.is_a?(Array)
560
- path, name, options, route_options = *parse_route(path, route_options, verb)
606
+ action = path
607
+ path, name, route_parents, options, route_options = *parse_route(path, route_options, verb)
561
608
  options.reverse_merge!(@_conditions) if @_conditions
562
609
 
563
610
  # Sinatra defaults
@@ -572,20 +619,22 @@ module Padrino
572
619
 
573
620
  # HTTPRouter route construction
574
621
  route = router.add(path, route_options)
575
- route.name(name) if name
622
+ route.name = name if name
623
+ route.action = action
576
624
  priority_name = options.delete(:priority) || :normal
577
625
  priority = ROUTE_PRIORITY[priority_name] or raise("Priority #{priority_name} not recognized, try #{ROUTE_PRIORITY.keys.join(', ')}")
578
626
  route.cache = options.key?(:cache) ? options.delete(:cache) : @_cache
579
- route.send(verb.downcase.to_sym)
580
- route.host(options.delete(:host)) if options.key?(:host)
581
- route.user_agent(options.delete(:agent)) if options.key?(:agent)
627
+ route.parent = route_parents ? (route_parents.count == 1 ? route_parents.first : route_parents) : route_parents
628
+ route.add_request_method(verb.downcase.to_sym)
629
+ route.host = options.delete(:host) if options.key?(:host)
630
+ route.user_agent = options.delete(:agent) if options.key?(:agent)
582
631
  if options.key?(:default_values)
583
632
  defaults = options.delete(:default_values)
584
- route.default(defaults) if defaults
633
+ route.add_default_values(defaults) if defaults
585
634
  end
586
635
  options.delete_if do |option, args|
587
- if route.send(:significant_variable_names).include?(option)
588
- route.matching(option => Array(args).first)
636
+ if route.significant_variable_names.include?(option)
637
+ route.add_match_with(option => Array(args).first)
589
638
  true
590
639
  end
591
640
  end
@@ -646,8 +695,8 @@ module Padrino
646
695
 
647
696
  if @_use_format or format_params = options[:provides]
648
697
  process_path_for_provides(path, format_params)
649
- options[:matching] ||= {}
650
- options[:matching][:format] = /[^\.]+/
698
+ # options[:add_match_with] ||= {}
699
+ # options[:add_match_with][:format] = /[^\.]+/
651
700
  end
652
701
 
653
702
  absolute_map = map && map[0] == ?/
@@ -657,14 +706,14 @@ module Padrino
657
706
  if map.blank? and !absolute_map
658
707
  controller_path = controller.join("/")
659
708
  path.gsub!(%r{^\(/\)|/\?}, "")
660
- path = File.join(controller_path, path)
709
+ path = File.join(controller_path, path) unless @_map
661
710
  end
662
711
  # Here we build the correct name route
663
712
  end
664
713
 
665
714
  # Now we need to parse our 'parent' params and parent scope
666
715
  if !absolute_map and parent_params = options.delete(:parent) || @_parents
667
- parent_params = Array(@_parents) + Array(parent_params)
716
+ parent_params = (Array(@_parents) + Array(parent_params)).uniq
668
717
  path = process_path_for_parent_params(path, parent_params)
669
718
  end
670
719
 
@@ -692,7 +741,7 @@ module Padrino
692
741
  # Merge in option defaults
693
742
  options.reverse_merge!(:default_values => @_defaults)
694
743
 
695
- [path, name, options, route_options]
744
+ [path, name, parent_params, options, route_options]
696
745
  end
697
746
 
698
747
  ##
@@ -758,7 +807,7 @@ module Padrino
758
807
  condition do
759
808
  mime_types = types.map { |t| mime_type(t) }
760
809
  url_format = params[:format].to_sym if params[:format]
761
- accepts = request.accept.map { |a| a.split(";")[0].strip }
810
+ accepts = request.accept.map { |a| a.to_str }
762
811
 
763
812
  # per rfc2616-sec14:
764
813
  # Assume */* if no ACCEPT header is given.
@@ -793,6 +842,21 @@ module Padrino
793
842
  matched_format
794
843
  end
795
844
  end
845
+
846
+ ##
847
+ # Implements CSRF checking when `allow_disabled_csrf` is set to true.
848
+ #
849
+ # This condition is always on, except when it is explicitly switched
850
+ # off.
851
+ #
852
+ # @example
853
+ # post("/", :csrf_protection => false)
854
+ #
855
+ def csrf_protection(on = true)
856
+ if on
857
+ condition { halt 403 if request.env['protection.csrf.failed'] }
858
+ end
859
+ end
796
860
  end
797
861
 
798
862
  ##
@@ -836,7 +900,7 @@ module Padrino
836
900
  else
837
901
  path_params << params
838
902
  end
839
- @route.url(*path_params)
903
+ @route.path(*path_params)
840
904
  end
841
905
 
842
906
  ##
@@ -905,13 +969,19 @@ module Padrino
905
969
  end
906
970
 
907
971
  def dispatch!
908
- static! if settings.static? && (request.get? || request.head?)
909
- route!
972
+ invoke do
973
+ static! if settings.static? && (request.get? || request.head?)
974
+ route!
975
+ end
910
976
  rescue ::Exception => boom
911
- filter! :before
912
- handle_exception!(boom)
977
+ filter! :before if boom.kind_of? ::Sinatra::NotFound
978
+ invoke { @boom_handled = handle_exception!(boom) }
913
979
  ensure
914
- filter! :after unless env['sinatra.static_file']
980
+ @boom_handled or begin
981
+ filter! :after unless env['sinatra.static_file']
982
+ rescue ::Exception => boom
983
+ invoke { handle_exception!(boom) } unless @env['sinatra.error']
984
+ end
915
985
  end
916
986
 
917
987
  def route!(base=settings, pass_block=nil)
@@ -919,9 +989,10 @@ module Padrino
919
989
  if base.compiled_router and match = base.compiled_router.call(@request.env)
920
990
  if match.respond_to?(:each)
921
991
  route_eval do
922
- match[1].each {|k,v| response[k] = v}
992
+ match[1].each { |k,v| response[k] = v }
923
993
  status match[0]
924
994
  route_missing if match[0] == 404
995
+ route_missing if allow = response['Allow'] and allow.include?(request.env['REQUEST_METHOD'])
925
996
  end
926
997
  end
927
998
  else
@@ -6,17 +6,18 @@ module Padrino
6
6
  class Base < Thor
7
7
  include Thor::Actions
8
8
 
9
- class_option :chdir, :type => :string, :aliases => "-c", :desc => "Change to dir before starting"
10
- class_option :environment, :type => :string, :aliases => "-e", :required => true, :default => :development, :desc => "Padrino Environment"
9
+ class_option :chdir, :type => :string, :aliases => "-c", :desc => "Change to dir before starting."
10
+ class_option :environment, :type => :string, :aliases => "-e", :required => true, :default => :development, :desc => "Padrino Environment."
11
11
  class_option :help, :type => :boolean, :desc => "Show help usage"
12
12
 
13
- desc "start", "Starts the Padrino application"
14
- method_option :server, :type => :string, :aliases => "-a", :desc => "Rack Handler (default: autodetect)"
15
- method_option :host, :type => :string, :aliases => "-h", :required => true, :default => "0.0.0.0", :desc => "Bind to HOST address"
16
- method_option :port, :type => :numeric, :aliases => "-p", :required => true, :default => 3000, :desc => "Use PORT"
17
- method_option :daemonize, :type => :boolean, :aliases => "-d", :desc => "Run daemonized in the background"
18
- method_option :pid, :type => :string, :aliases => "-i", :desc => "File to store pid"
19
- method_option :debug, :type => :boolean, :desc => "Set debugging flags"
13
+ desc "start", "Starts the Padrino application (alternatively use 's')."
14
+ map "s" => :start
15
+ method_option :server, :type => :string, :aliases => "-a", :desc => "Rack Handler (default: autodetect)"
16
+ method_option :host, :type => :string, :aliases => "-h", :required => true, :default => '127.0.0.1', :desc => "Bind to HOST address."
17
+ method_option :port, :type => :numeric, :aliases => "-p", :required => true, :default => 3000, :desc => "Use PORT."
18
+ method_option :daemonize, :type => :boolean, :aliases => "-d", :desc => "Run daemonized in the background."
19
+ method_option :pid, :type => :string, :aliases => "-i", :desc => "File to store pid."
20
+ method_option :debug, :type => :boolean, :desc => "Set debugging flags."
20
21
  def start
21
22
  prepare :start
22
23
  require File.expand_path("../adapter", __FILE__)
@@ -24,12 +25,8 @@ module Padrino
24
25
  Padrino::Cli::Adapter.start(options)
25
26
  end
26
27
 
27
- desc "s", "Starts the Padrino application"
28
- def s
29
- invoke :start
30
- end
31
-
32
- desc "stop", "Stops the Padrino application"
28
+ desc "stop", "Stops the Padrino application (alternatively use 'st')."
29
+ map "st" => :stop
33
30
  method_option :pid, :type => :string, :aliases => "-p", :desc => "File to store pid", :default => 'tmp/pids/server.pid'
34
31
  def stop
35
32
  prepare :stop
@@ -37,7 +34,7 @@ module Padrino
37
34
  Padrino::Cli::Adapter.stop(options)
38
35
  end
39
36
 
40
- desc "rake", "Execute rake tasks"
37
+ desc "rake", "Execute rake tasks."
41
38
  method_option :environment, :type => :string, :aliases => "-e", :required => true, :default => :development
42
39
  method_option :list, :type => :string, :aliases => "-T", :desc => "Display the tasks (matching optional PATTERN) with descriptions, then exit."
43
40
  method_option :trace, :type => :boolean, :aliases => "-t", :desc => "Turn on invoke/execute tracing, enable full backtrace."
@@ -51,12 +48,15 @@ module Padrino
51
48
  ARGV.concat(args)
52
49
  puts "=> Executing Rake #{ARGV.join(' ')} ..."
53
50
  load File.expand_path('../rake.rb', __FILE__)
54
- require File.expand_path('config/boot.rb')
55
- PadrinoTasks.init(true)
51
+ Rake.application.init
52
+ Rake.application.instance_variable_set(:@rakefile, __FILE__)
53
+ load File.expand_path('Rakefile')
54
+ Rake.application.top_level
56
55
  end
57
56
 
58
- desc "console", "Boots up the Padrino application irb console"
59
- def console
57
+ desc "console", "Boots up the Padrino application irb console (alternatively use 'c')."
58
+ map "c" => :console
59
+ def console(*args)
60
60
  prepare :console
61
61
  require File.expand_path("../../version", __FILE__)
62
62
  ARGV.clear
@@ -68,12 +68,8 @@ module Padrino
68
68
  IRB.start
69
69
  end
70
70
 
71
- desc "c", "Boots up the Padrino application irb console"
72
- def c(*args)
73
- invoke(:console, args)
74
- end
75
-
76
- desc "generate", "Executes the Padrino generator with given options."
71
+ desc "generate", "Executes the Padrino generator with given options (alternatively use 'gen' or 'g')."
72
+ map ["gen", "g"] => :generate
77
73
  def generate(*args)
78
74
  # Build Padrino g as an alias of padrino-gen
79
75
  begin
@@ -90,23 +86,30 @@ module Padrino
90
86
  end
91
87
  end
92
88
 
93
- desc "g", "Executes the Padrino generator with given options."
94
- def g(*args)
95
- invoke(:generate, args)
96
- end
97
-
98
- desc "gen", "Executes the Padrino generator with given options."
99
- def gen(*args)
100
- invoke(:generate, args)
101
- end
102
-
103
- desc "version", "Show current Padrino Version"
104
- map "-v" => :version, "--version" => :version
89
+ desc "version", "Show current Padrino version."
90
+ map ["-v", "--version"] => :version
105
91
  def version
106
92
  require 'padrino-core/version'
107
93
  puts "Padrino v. #{Padrino.version}"
108
94
  end
109
95
 
96
+ desc "runner", "Run a piece of code in the Padrino application environment (alternatively use 'run' or 'r')."
97
+ map ["run", "r"] => :runner
98
+ def runner(*args)
99
+ prepare :runner
100
+
101
+ code_or_file = args.shift
102
+ abort "Please specify code or file" if code_or_file.nil?
103
+
104
+ require File.expand_path('config/boot.rb')
105
+
106
+ if File.exist?(code_or_file)
107
+ eval(File.read(code_or_file), nil, code_or_file)
108
+ else
109
+ eval(code_or_file)
110
+ end
111
+ end
112
+
110
113
  private
111
114
  def prepare(task)
112
115
  if options.help?