diff --git a/active_record.rb b/active_record.rb new file mode 100644 index 0000000..ca63128 --- /dev/null +++ b/active_record.rb @@ -0,0 +1,47 @@ +require "connection_adapter" + +module ActiveRecord + class Base + @@connection = SqliteAdapter.new + + def initialize(attributes) + @attributes = attributes + end + + def method_missing(name, *args) + if self.class.columns.include?(name) + @attributes[name] + else + super + end + end + + def self.find(id) + find_by_sql("SELECT * FROM #{table_name} WHERE id = #{id.to_i} LIMIT 1").first + end + + def self.all + find_by_sql("SELECT * FROM #{table_name}") + end + + def self.find_by_sql(sql) + rows = @@connection.execute(sql) + rows.map do |row| + attributes = map_values_to_columns(row) + new(attributes) + end + end + + def self.map_values_to_columns(values) + Hash[columns.zip(values)] + end + + def self.columns + @@connection.columns(table_name) + end + + def self.table_name + name.downcase + "s" # users + end + end +end \ No newline at end of file diff --git a/config.ru b/config.ru index 68623d6..da23dc3 100644 --- a/config.ru +++ b/config.ru @@ -1,7 +1,4 @@ -class App - def call(env) - # Return the response array here - end -end +$:.unshift "." +require "front_controller" -run App.new \ No newline at end of file +run FrontController.new \ No newline at end of file diff --git a/controller.rb b/controller.rb new file mode 100644 index 0000000..9cb11bb --- /dev/null +++ b/controller.rb @@ -0,0 +1,30 @@ +require "active_record" +require "filters" + +class Controller + attr_accessor :request, :response + + include Filters + + def render(action) + @rendered = true + response.write render_to_string(action) + end + + def rendered? + @rendered + end + + def render_to_string(action) + path = template_path(action) + ERB.new(File.read(path)).result(binding) + end + + def template_path(action) + File.dirname(__FILE__) + "/views/#{controller_name}/#{action}.erb" + end + + def controller_name + self.class.name[/^(\w+)Controller$/, 1].downcase # home + end +end \ No newline at end of file diff --git a/controllers/echo_controller.rb b/controllers/echo_controller.rb new file mode 100644 index 0000000..aac0db5 --- /dev/null +++ b/controllers/echo_controller.rb @@ -0,0 +1,5 @@ +class EchoController < Controller + def index + response.write "You said: " + request["text"] + end +end \ No newline at end of file diff --git a/controllers/home_controller.rb b/controllers/home_controller.rb new file mode 100644 index 0000000..18f9d5c --- /dev/null +++ b/controllers/home_controller.rb @@ -0,0 +1,28 @@ +class HomeController < Controller + before_filter :header + after_filter :footer + around_filter :layout + + def index + @message = "Hi from home controller" + render :index + end + + def nice + response.write "This is nice" + end + + def header + response.write "

My App

" + end + + def footer + response.write "

© me

" + end + + def layout + response.write "" + yield + response.write "" + end +end \ No newline at end of file diff --git a/controllers/users_controller.rb b/controllers/users_controller.rb new file mode 100644 index 0000000..7374c90 --- /dev/null +++ b/controllers/users_controller.rb @@ -0,0 +1,14 @@ +require "models/user" + +class UsersController < Controller + def index + User.all.each do |user| + response.write "

#{user.name}

" + end + end + + def show + user = User.find(request["id"]) + response.write "

#{user.name}

" + end +end \ No newline at end of file diff --git a/filters.rb b/filters.rb new file mode 100644 index 0000000..2443e71 --- /dev/null +++ b/filters.rb @@ -0,0 +1,40 @@ +require "active_support/all" + +module Filters + def self.included(base) + base.extend ClassMethods + base.class_attribute :before_filters + base.before_filters = [] + base.class_attribute :after_filters + base.after_filters = [] + base.class_attribute :around_filters + base.around_filters = [] + end + + module ClassMethods + def before_filter(method) + self.before_filters += [method] + end + def after_filter(method) + self.after_filters += [method] + end + def around_filter(method) + self.around_filters += [method] + end + end + + def filter + process_proc = proc do + before_filters.each { |method| send(method) } + yield + after_filters.each { |method| send(method) } + end + + around_filters.reverse.each do |method| + current_proc = process_proc + process_proc = proc { send(method, ¤t_proc) } + end + + process_proc.call + end +end diff --git a/front_controller.rb b/front_controller.rb new file mode 100644 index 0000000..ecb4212 --- /dev/null +++ b/front_controller.rb @@ -0,0 +1,31 @@ +require "controller" + +class FrontController + def call(env) + request = Rack::Request.new(env) + response = Rack::Response.new + + controller_name, action_name = route(request.path_info) + controller_class = load_controller_class(controller_name) + + controller = controller_class.new + controller.request = request + controller.response = response + controller.filter do + controller.send(action_name) + controller.render(action_name) unless controller.rendered? + end + + response.finish + end + + def route(path) + _, controller_name, action_name = path.split("/") # "", "home", "index" + [controller_name || "home", action_name || "index"] + end + + def load_controller_class(name) + require "controllers/#{name}_controller" + Object.const_get(name.capitalize + "Controller") # HomeController + end +end \ No newline at end of file diff --git a/models/user.rb b/models/user.rb new file mode 100644 index 0000000..3ef3aba --- /dev/null +++ b/models/user.rb @@ -0,0 +1,3 @@ +class User < ActiveRecord::Base + +end \ No newline at end of file diff --git a/tests/connection_adapter_test.rb b/tests/connection_adapter_test.rb index 2f885e1..fab8609 100644 --- a/tests/connection_adapter_test.rb +++ b/tests/connection_adapter_test.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/test_helper' +require File.expand_path('test_helper', File.dirname(__FILE__)) require "connection_adapter" class ConnectionAdapterTest < Test::Unit::TestCase @@ -14,4 +14,4 @@ def test_execute def test_columns assert_equal [:id, :name], @adapter.columns("users") end -end \ No newline at end of file +end diff --git a/tests/controller_test.rb b/tests/controller_test.rb new file mode 100644 index 0000000..15e29ad --- /dev/null +++ b/tests/controller_test.rb @@ -0,0 +1,22 @@ +require File.expand_path('test_helper', File.dirname(__FILE__)) +require "controller" +require "controllers/home_controller" + +class ControllerTest < Test::Unit::TestCase + def setup + @controller = HomeController.new + end + + def test_template_path + assert_equal File.expand_path("../../views/home/index.erb", __FILE__), + @controller.template_path("index") + end + + def test_controller_name + assert_equal "home", @controller.controller_name + end + + def test_render_to_string + assert_not_nil @controller.render_to_string("index") + end +end diff --git a/tests/filters_test.rb b/tests/filters_test.rb new file mode 100644 index 0000000..cc9daa6 --- /dev/null +++ b/tests/filters_test.rb @@ -0,0 +1,54 @@ +require File.expand_path('test_helper', File.dirname(__FILE__)) +require "controller" + +class TestController < Controller + around_filter :around1 + around_filter :around2 + before_filter :one + before_filter :two + after_filter :three + + def initialize(out) + @out = out + end + + def one + @out << :one + end + + def two + @out << :two + end + + def three + @out << :three + end + + def around1 + @out << "{" + yield + @out << "}" + end + + def around2 + @out << "[" + yield + @out << "]" + end +end + +class FiltersTest < Test::Unit::TestCase + def test_store_filters + assert_equal [:one, :two], TestController.before_filters + assert_equal [:three], TestController.after_filters + assert_equal [:around1, :around2], TestController.around_filters + end + + def test_filter + out = [] + TestController.new(out).filter do + out << :process + end + assert_equal ["{", "[", :one, :two, :process, :three, "]", "}"], out + end +end diff --git a/tests/front_controller_test.rb b/tests/front_controller_test.rb new file mode 100644 index 0000000..151f4b8 --- /dev/null +++ b/tests/front_controller_test.rb @@ -0,0 +1,20 @@ +require File.expand_path('test_helper', File.dirname(__FILE__)) +require "front_controller" + +class FrontControllerTest < Test::Unit::TestCase + def setup + @front = FrontController.new + end + + def test_routing + assert_equal ["home", "index"], @front.route("/home/index") + assert_equal ["home", "index"], @front.route("/") + assert_equal ["hello", "index"], @front.route("/hello") + assert_equal ["hello", "there"], @front.route("/hello/there") + end + + def test_load_controller_class + klass = @front.load_controller_class("home") + assert_equal HomeController, klass + end +end diff --git a/tests/user_test.rb b/tests/user_test.rb new file mode 100644 index 0000000..fe78559 --- /dev/null +++ b/tests/user_test.rb @@ -0,0 +1,40 @@ +require File.expand_path('test_helper', File.dirname(__FILE__)) +require "active_record" +require "models/user" + +class UserTest < Test::Unit::TestCase + def test_initalize_with_attributes + user = User.new(:id => 1, :name => "Marc") + assert_equal 1, user.id + assert_equal "Marc", user.name + end + + def test_find + user = User.find(1) + assert_equal 1, user.id + end + + def test_all + user = User.all.first + assert_equal 1, user.id + end + + def test_map_values_to_columns + columns = [:id, :name] + values = [1, "Marc"] + + expected = { :id => 1, :name => "Marc" } + + attributes = User.map_values_to_columns(values) + + assert_equal expected, attributes + end + + def test_columns + assert_equal [:id, :name], User.columns + end + + def test_table_name + assert_equal "users", User.table_name + end +end diff --git a/views/home/index.erb b/views/home/index.erb new file mode 100644 index 0000000..27a2447 --- /dev/null +++ b/views/home/index.erb @@ -0,0 +1,2 @@ +

Hello from a view

+

<%= @message %>

\ No newline at end of file