Skip to content
Permalink
Browse files

Initial commit

  • Loading branch information...
chrismccord committed Jan 18, 2014
0 parents commit c4ede8c5f71ab74b0c2e9de1eb37d15531d95a46
@@ -0,0 +1,4 @@
/_build
/deps
erl_crash.dump
*.ez
@@ -0,0 +1,3 @@
# Phoenix

** TODO: Add description **
@@ -0,0 +1,9 @@
defmodule Phoenix do
use Application.Behaviour

# See http://elixir-lang.org/docs/stable/Application.Behaviour.html
# for more information on OTP Applications
def start(_type, _args) do
Phoenix.Supervisor.start_link
end
end
@@ -0,0 +1,18 @@
defrecord Phoenix.Request, foo: :bar

# authorization
# body
# content_length, cookie_jar
# flash
# fullpath
# headers
# ip
# media_type, method, method_symbol
# original_fullpath, original_url
# parse_query, patch?, post?, put?
# query_parameters
# method,
# parameters
# uuid
# xhr,
# xml_http_request
@@ -0,0 +1,83 @@
defmodule Phoenix.Router.Mapper do
alias Phoenix.Router.Params
alias Phoenix.Router.Path

@moduledoc """
get "/", :pages, :home, as: :home
map :users, only: [:show] do
map :comments, only: [:get, :post]
end
"""

defmacro __using__(_options) do
quote do
Module.register_attribute __MODULE__, :routes, accumulate: true,
persist: false
import unquote(__MODULE__)

@before_compile unquote(__MODULE__)
end
end

defmacro __before_compile__(env) do
routes = Enum.reverse(Module.get_attribute(env.module, :routes))
Enum.reduce routes, nil, fn route, acc ->
quote do
defmatch(unquote(route))
defroute_aliases(unquote(route))
unquote(acc)
end
end
end

defmacro defmatch({http_method, path, controller, action, options}) do
path_args = Path.matched_arg_list_with_ast_bindings(path)
params_list_with_bindings = Path.params_with_ast_bindings(path)

ast = quote do
def unquote(:match)(conn, unquote(http_method), unquote(path_args)) do
{unquote(controller), unquote(action), unquote(options)}
params = unquote(params_list_with_bindings)

{:ok, conn
|> Plug.Connection.put_resp_content_type("text/plain")
|> Plug.Connection.send(200, "Matched Params: #{inspect params}")
}
end
end
# IO.puts Macro.to_string(ast)

ast
end

defmacro defroute_aliases({http_method, path, controller, action, options}) do
alias_name = options[:as]
quote do
if unquote(alias_name) do
def unquote(binary_to_atom "#{alias_name}_path")(), do: unquote(path)
def unquote(binary_to_atom "#{alias_name}_url")(), do: unquote(path)
end
end
end

defmacro get(path, controller, action, options // []) do
quote do
@routes {:get, unquote_splicing([path, controller, action, options])}
end
end

defmacro post(path, controller, action, options // []) do
quote do
@routes {:post, unquote_splicing([path, controller, action, options])}
end
end

defmacro resources(controller, options // []) when is_atom(controller) do
quote do
get unquote_splicing(["#{controller}/:id", controller, :show, options])
get unquote_splicing(["#{controller}", controller, :index, options])
post unquote_splicing(["#{controller}", controller, :create, options])
end
end
end
@@ -0,0 +1,66 @@
defmodule Phoenix.Router.Path do

def split(path) do
String.split(path, "/")
end

@doc """
Splits parameterized String path into list of arguments for defmatch route.
Named params beginning with ":" are injected into the argument list as
an AST binding matching the param name.
Examples
iex> Path.matched_arg_list_with_ast_bindings("users/:user_id/comments/:id")
["users", {:user_id, [], Elixir}, "comments", {:id, [], Elixir}]
Generated as:
def match(:get, ["users", user_id, "comments", id])
"""
def matched_arg_list_with_ast_bindings(path) do
path
|> split
|> Enum.map fn part ->
case part do
<<":" <> param_name>> -> {binary_to_atom(param_name), [], Elixir}
_ -> part
end
end
end

@doc """
Returns Keyword List of parameters from URL matched with
AST of associationed bindings for inclusion in defmatch route
Examples
iex> Path.params_with_bindings("users/:user_id/comments/:id")
[user_id: {:user_id, [], Elixir}, id: {:id, [], Elixir}]
"""
def params_with_ast_bindings(path) do
Enum.zip(param_names(path), matched_param_ast_bindings(path))
end

def matched_param_ast_bindings(path) do
path
|> matched_arg_list_with_ast_bindings
|> Enum.filter(&is_tuple(&1))
end

@doc """
Returns List of atoms of contained named parameters in route
Examples
iex> Phoenix.Router.Path.param_names("users/:user_id/comments/:id")
[:user_id, :id]
iex> Phoenix.Router.Path.param_names("/pages/about")
[]
"""
def param_names(path) do
Regex.scan(%r/:\w+/, path)
|> List.flatten
|> Enum.map(&String.strip(&1, ?:))
|> Enum.map(&binary_to_atom(&1))
end
end
@@ -0,0 +1,31 @@
defmodule Phoenix.Router do

defmacro __using__(plug_adapter_options // []) do
quote do
use Phoenix.Router.Mapper
import Plug.Connection
import unquote(__MODULE__)

@options unquote(plug_adapter_options)

def start do
IO.puts "Running #{__MODULE__} with Cowboy with #{inspect @options}"
Plug.Adapters.Cowboy.http __MODULE__, [], @options
end

def call(conn, []) do

This comment has been minimized.

Copy link
@josevalim

josevalim Feb 5, 2014

Member

Remember to inject as little code as possible. You can probably break have those two functions (start and call) delegating to some sort of Plug.Router.Backend.

conn = Plug.Connection.fetch_params(conn)
http_method = conn.method |> String.downcase |> binary_to_atom
split_path = conn.path_info
params = conn.params

IO.puts "#{__MODULE__}: #{http_method}: #{inspect split_path}"
dispatch(conn, __MODULE__, http_method, split_path)
end
end
end

def dispatch(conn, router, http_method, path) do
apply(router, :match, [conn, http_method, path])
end
end
@@ -0,0 +1,8 @@
defmodule AppRouter do
use Phoenix.Router, port: 4000

get "users/:user_id/comments/:id", :comments, :show
get "pages/:page", :pages, :show
end

AppRouter.start
@@ -0,0 +1,18 @@
defmodule Phoenix.Supervisor do
use Supervisor.Behaviour

def start_link do
:supervisor.start_link(__MODULE__, [])
end

def init([]) do
children = [
# Define workers and child supervisors to be supervised
# worker(Phoenix.Worker, [])
]

# See http://elixir-lang.org/docs/stable/Supervisor.Behaviour.html
# for other strategies and supported options
supervise(children, strategy: :one_for_one)
end
end
24 mix.exs
@@ -0,0 +1,24 @@
defmodule Phoenix.Mixfile do
use Mix.Project

def project do
[ app: :phoenix,
version: "0.0.1",
elixir: "~> 0.12.1",
deps: deps ]
end

def application do
[
mod: { Phoenix, [] },
applications: [:cowboy, :plug]
]
end

defp deps do
[
{:cowboy, github: "extend/cowboy"},
{:plug, github: "elixir-lang/plug"}
]
end
end
@@ -0,0 +1,4 @@
[ "cowboy": {:git, "git://github.com/extend/cowboy.git", "0ec713fc4b185c3cd0f6b2e7ec2c5f198361bddd", []},
"cowlib": {:git, "git://github.com/extend/cowlib.git", "63298e8e160031a70efff86a1acde7e7db1fcda6", [ref: "0.4.0"]},
"plug": {:git, "git://github.com/elixir-lang/plug.git", "b3d9327a066263b3a84875d1afb71fdb9bf2ac99", []},
"ranch": {:git, "git://github.com/extend/ranch.git", "5df1f222f94e08abdcab7084f5e13027143cc222", [ref: "0.9.0"]} ]
@@ -0,0 +1,7 @@
defmodule PhoenixTest do
use ExUnit.Case

test "the truth" do
assert(true)
end
end
@@ -0,0 +1 @@
ExUnit.start

0 comments on commit c4ede8c

Please sign in to comment.
You can’t perform that action at this time.