-
Notifications
You must be signed in to change notification settings - Fork 1
Rack app to display username and current time #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
RackApp/app.rb
Outdated
| if req.path.match('/users/hema') && req.params["tz"] == "IST" | ||
| user = User.new("hema") | ||
| time = CountryTime.new("Kolkata") | ||
| view = View.new(user, time) | ||
| ['200', {"Content-Type" => "text/html"}, [view.render]] | ||
| elsif | ||
| req.path.match('/users/hery') && req.params["tz"] == "UTC" | ||
| user = User.new("Hery") | ||
| time = CountryTime.new("Eastern Time (US & Canada)") | ||
| view = View.new(user, time) | ||
| ['200', {"Content-Type" => "text/html"}, [view.render]] | ||
| elsif | ||
| req.path.match('/users/Cadu') && req.params["tz"] == "AST" | ||
| user = User.new("Cadu") | ||
| time = CountryTime.new("Asia/Kuwait") | ||
| view = View.new(user, time) | ||
| ['200', {"Content-Type" => "text/html"}, [view.render]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those are quite similar, can you refactor?
RackApp/app.rb
Outdated
| class WebApp | ||
| def initialize | ||
|
|
||
| end | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class does nothing sadly, can you remove or add logic there?
RackApp/app.rb
Outdated
| @@ -0,0 +1,85 @@ | |||
| require 'erb' | |||
| require 'rack' | |||
| require 'active_support/all' | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do not need to require all active_support. Always require only the necessary library if it is small
RackApp/app.rb
Outdated
| require 'active_support/all' | ||
|
|
||
| class View | ||
| attr_reader :person, :time |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your editor is configured to use 4 spaces as indentation, for various reason and better readability use 2 spaces
RackApp/template.html.erb
Outdated
| <html> | ||
| <head> | ||
| <b> | ||
| persons nick name is <%= person.nickname%> and current time in the timezone is <%= time.timezone %> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add space inside the ERB tags
| persons nick name is <%= person.nickname%> and current time in the timezone is <%= time.timezone %> | |
| persons nick name is <%= person.nickname %> and current time in the timezone is <%= time.timezone %> |
RackApp/app.rb
Outdated
| class Display | ||
| def self.call(env) | ||
| req = Rack::Request.new(env) | ||
| if req.path.match('/users/hema') && req.params["tz"] == "IST" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So those are static values, can you make them dynamic?:
- Display what you have in path as the nickname
- Select the Timezone from the
tzparameter as timezone
RackApp/app.rb
Outdated
| require 'rack' | ||
| require 'active_support/all' | ||
|
|
||
| class View |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is more a controller than a view
RackApp/app.rb
Outdated
| @@ -0,0 +1,71 @@ | |||
| require "erb" | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to use rubocop to check for code styling ;)
You can make another commit for it
Example, rubocop will tell you to not forget about # frozen_string_literal: true
Some good reads why we use such tools: https://rubystyle.guide/
Also about the magic comment frozen_string_literal: true
https://www.mikeperham.com/2018/02/28/ruby-optimization-with-one-magic-comment/
This might go probably in Ruby 3.0 default https://bugs.ruby-lang.org/issues/11473 (still in discussion)
RackApp/app.rb
Outdated
| nickname = req.params["nickname"] | ||
| tz = req.params["tz"] | ||
| if req.path.match("/users") && nickname && tz | ||
| user = User.new("#{nickname}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can avoid String interpolation by using above nickane = params['nickname'].to_s and son on
| end | ||
|
|
||
| class CountryTime | ||
| attr_reader :zone, :timezone |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
attr_reader method creates a getter method within CountryTime class, getter class means/looks like this:
def timezone
@timezone
end
so by defining def timezone again, you're rewriting the created getter created by attr_reader :timezone
so either you use the created getter or create your own:
- created getter by
attr_reader :timezone
class CountryTime
attr_reader :zone, :timezone
def initialize(zone)
@zone = zone
Time.zone = zone
@timezone = Time.zone.now
end
end
- manually created "getter" by a method
class CountryTime
attr_reader :zone
def initialize(zone)
@zone = zone
end
def timezone
Time.zone = zone
Time.zone.now
end
end
I would prefer the first way in this case, so timezone is being generated only once, it the second case you would generate the timezone in every method call.
| if req.path.match('/users') && nickname && tz && f | ||
| user = User.new(nickname.to_s) | ||
| time = CountryTime.new(tz.to_s) | ||
| view = MyController.new(user, time) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why time is being sent to MyController as a parameter and then never used?
also format could be another parameter and then you would call just view.render
RackApp/app.rb
Outdated
| puts env.inspect | ||
| nickname = req.params['nickname'] | ||
| tz = req.params['tz'] | ||
| f = req.params['f'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
f is not the ideal name for a variable.. the code should be readable as a book, so the variable names should make some sense.. timezone instead of tz, format instead of f
RackApp/app.rb
Outdated
| end | ||
|
|
||
| def file(format) | ||
| File.read(File.join(__dir__, "template.#{format}.erb")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can take it a bit forward and check if the file actually exists.. if not, we can throw some meaningful error.
do you know how to do it? or should I help you for a bit? :)
RackApp/app.rb
Outdated
| def file(format) | ||
| File.read(File.join(__dir__, "template.#{format}.erb")) | ||
| end | ||
|
|
||
| def template(format) | ||
| ERB.new(file(format)) | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like belonging to another class, name it View or Template
Something like that
class MyController
# This next line could be extracted to a BaseController :)
class_attribute :template_name, instance_writer: false
template_name 'template'
def template(format)
Template.new(template_name, format)
end
end
# rest of the code
class Template
def initialize(name, format)
@erb = file(name, format)
end
def file(name, format)
File.read(File.join(__dir__, 'templates', "#{name}.#{format}.erb"))
end
end| personname = 'hema' | ||
| Time.zone = 'UTC' | ||
| puts @timezone = Time.zone.now | ||
| data = <<-HTML |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comparing the whole website is not the best idea. You would need to change this test every time you change a view HTML. Better to use https://apidock.com/ruby/Test/Unit/Assertions/assert_match and check for just small strings, something like:
assert_match "name is #{personname} and current", last_response.body
got the idea?
|
|
||
| def test_pagenotfound | ||
| get '/users/nickname' | ||
| assert_equal last_response.body, '<html><body><b><em>404 Page not found</em></b></body></html>' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the same as: 0c74d6c#r374548506
just check for 404 Page not found.
macejmic
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these are integration tests, there are useful to check "response" behaviour as you did.. user should see this message and HTML should include this and that.. but along with integration tests would be good to add some unit tests too.
something like: https://en.wikibooks.org/wiki/Ruby_Programming/Unit_testing
| if File.exist?(file_path) | ||
| File.read(file_path) | ||
| else | ||
| 'ERROR:The file doesnot exist' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
raise an error instead ;)
Otherwise the result of the file will be displayed to the User
It is better to catch the error when it is really necessary and not assuming what it should do
RackApp/lib/myproject/app.rb
Outdated
| def call(env) | ||
| @app&.call(env) | ||
| req = Rack::Request.new(env) | ||
| puts env.inspect |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can remove this when you are done
| assert_equal last_response.body, '<html><body><b><em>404 Page not found</em></b></body></html>' | ||
| end | ||
|
|
||
| def test_undefinedfileformat |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use underscores to separate words
| end | ||
| end | ||
|
|
||
| class View |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally I would like this class to be tested
| def initialize(zone) | ||
| @zone = zone | ||
| Time.zone = zone | ||
| @timezone = Time.zone.now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not get this, Time.zone.now will return an instance of Time.
Though the name timezone is in fact equal to zone
| timezone = req.params['timezone'] | ||
| format = req.params['format'] | ||
| nickname_match = req.path.match('/users/nickname/(\w+)') | ||
| nickname = nickname_match[1] if nickname_match |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| nickname = nickname_match[1] if nickname_match | |
| nickname = $1 |
| end | ||
| end | ||
|
|
||
| class CountryTime |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to test this class
What if I send an invalid timezone?
| user = User.new(nickname) | ||
| time = CountryTime.new(timezone.to_s) | ||
| view = MyController.new(user, time) | ||
| ['200', { 'Content-Type' => response_format(format) }, [view.render_template(format)]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if I send an invalid format?
| format = req.params['format'] | ||
| nickname_match = req.path.match('/users/nickname/(\w+)') | ||
| nickname = nickname_match[1] if nickname_match | ||
| if nickname && timezone && format |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should check about validity of the data more than the presence
RackApp/test/test.rb
Outdated
| end | ||
|
|
||
| def test_jsonoutput | ||
| puts Time.zone = 'UTC' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are assigning Time.zone to 'UTC', is it intended?
RackApp/test/test.rb
Outdated
|
|
||
| def test_jsonoutput | ||
| puts Time.zone = 'UTC' | ||
| puts @timezone = Time.zone.now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can remove the debugging lines when all is clean
|
|
||
| def test_undefinedfileformat | ||
| get '/users/nickname/hema?timezone=UTC&format=xtml' | ||
| assert_equal last_response.body, 'ERROR:The file doesnot exist' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would expect a status code 415 if the format does not exist
No description provided.