Class: Rubydojo::Lesson
- Inherits:
-
Object
- Object
- Rubydojo::Lesson
- Defined in:
- lib/rubydojo/lessons.rb
Constant Summary collapse
- LOADED_LESSONS =
[ new( id: "variables", title: "Variables & Constants", level: "Level 1: Ruby Essentials", description: "Understand the backbone of Ruby storage: local variables, constants, and basic methods.", explanation: <<~MARKDOWN, code_template: <<~RUBY, validation_code: <<~RUBY, raise "Local variable 'age' must be defined" unless binding.local_variable_defined?(:age) user_age = binding.local_variable_get(:age) raise "Variable 'age' should be 25, got \#{user_age.inspect}" unless user_age == 25 raise "Constant 'PLANET' must be defined" unless self.class.const_defined?(:PLANET) || binding.eval("defined?(PLANET)") planet_val = binding.eval("PLANET") raise "Constant 'PLANET' should be 'Earth', got \#{planet_val.inspect}" unless planet_val == "Earth" raise "Method 'greet' is not defined" unless respond_to?(:greet) greet_test = greet("Jayesh") raise "Method 'greet' should return 'Hello, Jayesh!', got \#{greet_test.inspect}" unless greet_test == "Hello, Jayesh!" RUBY hint: "Make sure you use double quotes for strings, and remember that methods in Ruby implicitly return the last statement." ), new( id: "arrays", title: "Collections & Arrays", level: "Level 2: Collections", description: "Master the structure of Ruby lists (Arrays) and how to query, append, and slice them.", explanation: <<~MARKDOWN, code_template: <<~RUBY, validation_code: <<~RUBY, raise "Method 'first_and_last' is not defined" unless respond_to?(:first_and_last) test_arr1 = [10, 20, 30, 40] res1 = first_and_last(test_arr1) raise "first_and_last([10, 20, 30, 40]) should return [10, 40], got \#{res1.inspect}" unless res1 == [10, 40] raise "Method 'add_element' is not defined" unless respond_to?(:add_element) test_arr2 = ["a", "b"] res2 = add_element(test_arr2, "c") raise "add_element(['a', 'b'], 'c') should return ['a', 'b', 'c'], got \#{res2.inspect}" unless res2 == ["a", "b", "c"] RUBY hint: "You can access the first element with arr[0] or arr.first, and the last with arr[-1] or arr.last. Use << to append." ), new( id: "iterators", title: "Enumerables & Iterators", level: "Level 2: Collections", description: "Learn how to use blocks to iterate, map, select, and reduce collections in a powerful way.", explanation: <<~MARKDOWN, code_template: <<~RUBY, validation_code: <<~RUBY, raise "Method 'double_numbers' is not defined" unless respond_to?(:double_numbers) res1 = double_numbers([2, 5, 10]) raise "double_numbers([2, 5, 10]) should return [4, 10, 20], got \#{res1.inspect}" unless res1 == [4, 10, 20] raise "Method 'filter_even' is not defined" unless respond_to?(:filter_even) res2 = filter_even([1, 2, 3, 4, 5, 6]) raise "filter_even([1, 2, 3, 4, 5, 6]) should return [2, 4, 6], got \#{res2.inspect}" unless res2 == [2, 4, 6] RUBY hint: "Remember to call map on the numbers array inside double_numbers: `numbers.map { |n| ... }`." ), new( id: "classes", title: "Object-Oriented Ruby", level: "Level 3: OOP", description: "Understand classes, instance variables, initializers, and attribute readers/writers.", explanation: <<~MARKDOWN, code_template: <<~RUBY, validation_code: <<~RUBY, raise "Class Developer is not defined" unless defined?(Developer) && Developer.is_a?(Class) dev = Developer.new("Jayesh", "Rails Intern") raise "Developer name is not readable" unless dev.respond_to?(:name) raise "Developer name is not writable" unless dev.respond_to?(:name=) raise "Developer role is not readable" unless dev.respond_to?(:role) raise "Developer name should be 'Jayesh', got \#{dev.name.inspect}" unless dev.name == "Jayesh" raise "Developer role should be 'Rails Intern', got \#{dev.role.inspect}" unless dev.role == "Rails Intern" dev.name = "Alex" raise "greet method not defined" unless dev.respond_to?(:greet) greeting = dev.greet expected = "Hello, I am Alex and I work as a Rails Intern!" raise "greet should return '\#{expected}', got \#{greeting.inspect}" unless greeting == expected RUBY hint: "Don't forget to use `attr_accessor :name, :role` at the top of your class, and interpolate variables in your greeting: `\"Hello, I am \#{name}...\"`." ), new( id: "blocks_procs_lambdas", title: "Blocks, Procs & Lambdas", level: "Level 3: OOP & Functions", description: "Understand closures in Ruby: how blocks yield code, and the differences between Procs and Lambdas.", explanation: <<~MARKDOWN, code_template: <<~RUBY, validation_code: <<~RUBY, raise "Method 'run_twice' is not defined" unless respond_to?(:run_twice) counter = 0 run_twice { counter += 1 } raise "run_twice should execute the block twice, counted: \#{counter}" unless counter == 2 # Test if run_twice handles no block given case begin run_twice rescue LocalJumpError => e raise "run_twice should check block_given? before yielding, otherwise it raises LocalJumpError!" end raise "format_usd is not defined" unless binding.local_variable_defined?(:format_usd) || binding.eval("defined?(format_usd)") fmt = binding.eval("format_usd") raise "format_usd should be a Lambda or Proc" unless fmt.is_a?(Proc) # Check return format res1 = fmt.call(10) raise "format_usd(10) should return '$10.00', got \#{res1.inspect}" unless res1 == "$10.00" res2 = fmt.call(4.5) raise "format_usd(4.5) should return '$4.50', got \#{res2.inspect}" unless res2 == "$4.50" RUBY hint: "To format a float with 2 decimal places in Ruby, use string formatting: `'%.2f' % value`." ), new( id: "metaprogramming", title: "Metaprogramming Basics", level: "Level 4: Advanced Ruby", description: "Learn Ruby's magical powers: calling methods dynamically using send, and defining them using define_method.", explanation: <<~MARKDOWN, code_template: <<~RUBY, validation_code: <<~RUBY, raise "Class SmartDevice is not defined" unless defined?(SmartDevice) && SmartDevice.is_a?(Class) device = SmartDevice.new raise "turn_on method should be defined on SmartDevice" unless device.respond_to?(:turn_on) raise "turn_off method should be defined on SmartDevice" unless device.respond_to?(:turn_off) val_on = device.turn_on val_off = device.turn_off raise "turn_on should return 'Device is ON', got \#{val_on.inspect}" unless val_on == "Device is ON" raise "turn_off should return 'Device is OFF', got \#{val_off.inspect}" unless val_off == "Device is OFF" raise "Method 'call_turn_on' is not defined" unless respond_to?(:call_turn_on) res = call_turn_on(device) raise "call_turn_on(device) should return 'Device is ON', got \#{res.inspect}" unless res == "Device is ON" RUBY hint: "Inside define_method, status will be :on or :off. You can convert it to string and format it: `'Device is ' + status.to_s.upcase`." ), new( id: "rails_idioms", title: "Rails Ruby Idioms & ActiveSupport", level: "Level 5: Ruby in Rails", description: "Learn how Rails extends Ruby under the hood and master core ActiveSupport helpers like blank?, presence, and Safe Navigation.", explanation: <<~MARKDOWN, code_template: <<~RUBY, validation_code: <<~RUBY, raise "Method 'clean_params' is not defined" unless respond_to?(:clean_params) raise "clean_params should return nil for empty hash" unless clean_params({}).nil? raise "clean_params should return nil for nil" unless clean_params(nil).nil? raise "clean_params should return the parameters if present" unless clean_params({ name: "Jayesh" }) == { name: "Jayesh" } raise "Method 'safe_user_name' is not defined" unless respond_to?(:safe_user_name) # Create mock user struct UserMock = Struct.new(:name) u1 = UserMock.new("Jayesh") u2 = UserMock.new("") u3 = UserMock.new(nil) u4 = nil res1 = safe_user_name(u1) raise "safe_user_name(u1) should return 'JAYESH', got \#{res1.inspect}" unless res1 == "JAYESH" res2 = safe_user_name(u2) raise "safe_user_name(u2) should return 'ANONYMOUS', got \#{res2.inspect}" unless res2 == "ANONYMOUS" res3 = safe_user_name(u3) raise "safe_user_name(u3) should return 'ANONYMOUS', got \#{res3.inspect}" unless res3 == "ANONYMOUS" res4 = safe_user_name(u4) raise "safe_user_name(u4) should return 'ANONYMOUS', got \#{res4.inspect}" unless res4 == "ANONYMOUS" RUBY hint: "Remember: `user&.name` returns nil safely if user is nil. You can check if the name is blank with `&.blank?`." ) ]
Instance Attribute Summary collapse
-
#code_template ⇒ Object
readonly
Returns the value of attribute code_template.
-
#description ⇒ Object
readonly
Returns the value of attribute description.
-
#explanation ⇒ Object
readonly
Returns the value of attribute explanation.
-
#hint ⇒ Object
readonly
Returns the value of attribute hint.
-
#id ⇒ Object
readonly
Returns the value of attribute id.
-
#level ⇒ Object
readonly
Returns the value of attribute level.
-
#title ⇒ Object
readonly
Returns the value of attribute title.
-
#validation_code ⇒ Object
readonly
Returns the value of attribute validation_code.
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(id:, title:, level:, description:, explanation:, code_template:, validation_code:, hint:) ⇒ Lesson
constructor
A new instance of Lesson.
Constructor Details
#initialize(id:, title:, level:, description:, explanation:, code_template:, validation_code:, hint:) ⇒ Lesson
Returns a new instance of Lesson.
5 6 7 8 9 10 11 12 13 14 |
# File 'lib/rubydojo/lessons.rb', line 5 def initialize(id:, title:, level:, description:, explanation:, code_template:, validation_code:, hint:) @id = id @title = title @level = level @description = description @explanation = explanation @code_template = code_template @validation_code = validation_code @hint = hint end |
Instance Attribute Details
#code_template ⇒ Object (readonly)
Returns the value of attribute code_template.
3 4 5 |
# File 'lib/rubydojo/lessons.rb', line 3 def code_template @code_template end |
#description ⇒ Object (readonly)
Returns the value of attribute description.
3 4 5 |
# File 'lib/rubydojo/lessons.rb', line 3 def description @description end |
#explanation ⇒ Object (readonly)
Returns the value of attribute explanation.
3 4 5 |
# File 'lib/rubydojo/lessons.rb', line 3 def explanation @explanation end |
#hint ⇒ Object (readonly)
Returns the value of attribute hint.
3 4 5 |
# File 'lib/rubydojo/lessons.rb', line 3 def hint @hint end |
#id ⇒ Object (readonly)
Returns the value of attribute id.
3 4 5 |
# File 'lib/rubydojo/lessons.rb', line 3 def id @id end |
#level ⇒ Object (readonly)
Returns the value of attribute level.
3 4 5 |
# File 'lib/rubydojo/lessons.rb', line 3 def level @level end |
#title ⇒ Object (readonly)
Returns the value of attribute title.
3 4 5 |
# File 'lib/rubydojo/lessons.rb', line 3 def title @title end |
#validation_code ⇒ Object (readonly)
Returns the value of attribute validation_code.
3 4 5 |
# File 'lib/rubydojo/lessons.rb', line 3 def validation_code @validation_code end |
Class Method Details
.all ⇒ Object
16 17 18 |
# File 'lib/rubydojo/lessons.rb', line 16 def self.all @all ||= LOADED_LESSONS end |
.find(id) ⇒ Object
20 21 22 |
# File 'lib/rubydojo/lessons.rb', line 20 def self.find(id) all.find { |l| l.id.to_s == id.to_s } end |
.next_lesson(current_id) ⇒ Object
24 25 26 27 28 |
# File 'lib/rubydojo/lessons.rb', line 24 def self.next_lesson(current_id) current_index = all.index { |l| l.id.to_s == current_id.to_s } return nil unless current_index && current_index < all.size - 1 all[current_index + 1] end |