Permalink
Browse files

Merge branch 'master' of git://github.com/evanmiller/ChicagoBoss into…

… multiple_listeners

Conflicts:
	src/boss/boss_web_controller.erl
  • Loading branch information...
majastanislawska committed Dec 5, 2011
2 parents ea9044f + 35647ba commit 4e620add6d02174709122459923ad98fc99793dc
@@ -8,15 +8,15 @@
&nbsp; <a href="#simplebridge">SimpleBridge request object</a></p>
<p>Chicago Boss associates each URL with a function of a controller.
The URL <nobr>/foo/bar</nobr> will call the function <code>foo_controller:bar</code>.
-Each controller module should go into your project's src/controller/ directory and the file name should end with "_controller.erl".
+Each controller module should go into your project's src/controller/ directory and the file name should start with the application name and end with "_controller.erl", e.g. "appname_my_controller.erl".
Helper functions should go into your project's src/lib/ directory.
Controllers can take one parameter or two parameters: the <a href="#simplebridge">SimpleBridge request object</a>, and an optional session ID (if <a href="api-session.html">sessions</a> are enabled). Declare it like:</p>
<div class="code">
- <span class="attr">-module</span>(my_controller, [Req]).
+ <span class="attr">-module</span>(appname_my_controller, [Req]).
</div>
-Or:
+<p>Or:</p>
<div class="code">
- <span class="attr">-module</span>(my_controller, [Req, SessionID]).
+ <span class="attr">-module</span>(appname_my_controller, [Req, SessionID]).
</div>
<p>Each exported controller function takes two or three arguments:</p>
<ul>
@@ -60,7 +60,7 @@
<a name="routes"></a>
<h3>Routes</h3>
-<p>Most routing takes place in the controller pattern-matching code. You can define additional routes in <code>priv/my_application.routes</code>. The file contains a list of erlang terms, one per line finished with a dot. Each term is a tuple with a URL or an HTTP status code as the first term, and a <code>{Controller, Action}</code> or <code>{Controller, Action, Parameters}</code> tuple as the second term.</p>
+<p>Most routing takes place in the controller pattern-matching code. You can define additional routes in <code>priv/my_application.routes</code>. The file contains a list of erlang terms, one per line finished with a dot. Each term is a tuple with a URL or an HTTP status code as the first term, and a <code>{Controller::string(), Action::string()}</code> or <code>{Controller::string(), Action::string(), Parameters::proplist()}</code> tuple as the second term.</p>
<p>A few examples:</p>
@@ -81,21 +81,22 @@ <h3>Authorization</h3>
<p>If an action takes three arguments, then the function <code>before_/1</code> in your controller will be passed the action name as a string and should return one of:</P>
-<div class="code">
+<div class="code spec">
{ok, ExtraInfo}
</div>
<p><code>ExtraInfo</code> will be passed as the third argument to the action, and as a variable called "before_" to the templates.</p>
-<div class="code">
+<div class="code spec">
{redirect, Location}
</div>
+<p><code>Location = string() | [{Key<span class="typevar">::atom()</span>, Value<span class="typevar">::atom()</span>}]</code></p>
<p>Do not execute the action. Instead, perform a 302 redirect to <code>Location</code>, which can be a string or a proplist that will be converted to a URL using the routes system.</p>
<p>Probably most common before_ looks like:</p>
-<div class="code">
+<div class="code spec">
before_(_) -&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span class="function">my_user_lib</span>:<span class="function">require_login</span>(Req).
</div>
@@ -108,78 +109,77 @@ <h3>Return values</h3>
<p>Whether or not it takes a third argument, a controller action should return with one of the following:</p>
-<div class="code">
+<div class="code spec">
ok
</div>
<p>The template will be rendered without any variables.</p>
-<div class="code">
+<div class="code spec">
{ok, Variables<span class="typevar">::proplist()</span>}
</div>
<p><code>Variables</code> will be passed into the associated <a href="api-view.html#nav">Django template</a>.</p>
-<div class="code">
+<div class="code spec">
{ok, Variables<span class="typevar">::proplist()</span>, Headers<span class="typevar">::proplist()</span>}
</div>
<p><code>Variables</code> will be passed into the associated Django template, and <code>Headers</code> are HTTP headers you want to set (e.g., <code>Content-Type</code>).</p>
-<div class="code">
+<div class="code spec">
{redirect, Location}
</div>
+<p><code>Location = string() | [{action, Value<span class="typevar">::string()</span>}, ...]</code></p>
<p>Perform a 302 HTTP redirect to <code>Location</code>, which may be a URL string or a proplist of parameters that will be converted to a URL using the routes system.</p>
-<div class="code">
+<div class="code spec">
{redirect, Location, Headers<span class="typevar">::proplist()</span>}
</div>
<p>Perform a 302 HTTP redirect to <code>Location</code> and set additional HTTP <code>Headers</code>.</p>
-<div class="code">
+<div class="code spec">
{action_other, OtherLocation}
</div>
-<p><code>OtherLocation = {Controller<span class="typevar">::atom()</span>, Action<span class="typevar">::atom()</span>}</code></p>
+<p><code>OtherLocation = [{action, Value<span class="typevar">::string()</span>}, ...]</code></p>
-<p>Execute the specified controller action, but without performing an HTTP redirect.</p>
+<p>Execute the controller action specified by <code>OtherLocation</code>, but without performing an HTTP redirect.</p>
-<div class="code">
+<div class="code spec">
{render_other, OtherLocation}
</div>
-<p><code>OtherLocation = {Controller<span class="typevar">::atom()</span>, Action<span class="typevar">::atom()</span>}</code></p>
+<p><code>OtherLocation = [{action, Value<span class="typevar">::string()</span>}, ...]</code></p>
<p>Render the view from <code>OtherLocation</code>, but don't actually execute the associated controller action.</p>
-<div class="code">
+<div class="code spec">
{render_other, OtherLocation, Variables}
</div>
-<p><code>OtherLocation = {Controller<span class="typevar">::atom()</span>, Action<span class="typevar">::atom()</span>}</code></p>
-
<p>Render the view from <code>OtherLocation</code> using <code>Variables</code>, but don't actually execute the associated controller action.</p>
-<div class="code">
+<div class="code spec">
{output, Output<span class="typevar">::iolist()</span>}
</div>
<p>Skip views altogether and return <code>Output</code> to the client.</p>
-<div class="code">
+<div class="code spec">
{output, Output<span class="typevar">::iolist()</span>, Headers<span class="typevar">::proplist()</span>}
</div>
<p>Skip views altogether and return <code>Output</code> to the client while setting additional HTTP <code>Headers</code>.</p>
-<div class="code">
+<div class="code spec">
{json, Data<span class="typevar">::proplist()</span>}
</div>
<p>Return <code>Data</code> as a JSON object to the client. Performs appropriate serialization if the values in Data contain a BossRecord or a list of BossRecords.</p>
-<div class="code">
+<div class="code spec">
{json, Data<span class="typevar">::proplist()</span>, Headers<span class="typevar">::proplist()</span>}
</div>
<p>Return <code>Data</code> to the client as a JSON object while setting additional HTTP <code>Headers</code>.</p>
-<div class="code">
+<div class="code spec">
not_found
</div>
@@ -195,12 +195,12 @@ <h3>Post-processing</h3>
<li>The result of the before_ function, provided one exists</li>
</ol>
<p>The <code>after_</code> function should return a (possibly) modified HTTP result tuple. Result tuples may be one of:</p>
-<div class="code">
+<div class="code spec">
{redirect, Location<span class="typevar">::string()</span>, Headers<span class="typevar">::proplist()</span>}
</div>
<p>Performs a 302 HTTP redirect to <code>Location</code> and sets additional HTTP <code>Headers</code>.</p>
-<div class="code">
+<div class="code spec">
{ok, Payload<span class="typevar">::iolist()</span>, Headers<span class="typevar">::proplist()</span>}
</div>
<p>Returns a 200 OK response to the client with <code>Payload</code> as the HTTP body, and sets additional HTTP <code>Headers</code>.</p>
@@ -210,36 +210,36 @@ <h3>SimpleBridge</h3>
<p>Controller functions are passed a SimpleBridge request object (slightly modified for Boss's purposes). Useful functions in the request object include:</p>
-<div class="code">
+<div class="code spec">
request_method() -&gt; atom()
</div>
<p>Get the request method, e.g. GET, POST, etc.</p>
-<div class="code">
+<div class="code spec">
query_param( Key<span class="typevar">::string()</span> ) -&gt; string() | undefined
</div>
<p>Get the value of a given query string parameter (e.g. "?id=1234")</p>
-<div class="code">
+<div class="code spec">
post_param( Key<span class="typevar">::string()</span> ) -&gt; string() | undefined
</div>
<p>Get the value of a given POST parameter</p>
-<div class="code">
+<div class="code spec">
deep_post_param( [ Path<span class="typevar">::string()</span> ] ) -&gt; DeepParam | undefined
</div>
<p>Get the value of a given "deep" POST parameter.
This function parses parameters that have numerical or labeled indices, such as "widget[4][name]", and returns either a value or a set of nested lists (for numerical indices) and proplists (for string indices).</p>
-<div class="code">
- header( Key<span class="typevar">::atom()</span> ) -&gt; string() | undefined
+<div class="code spec">
+ header( Header<span class="typevar">::string()</span> | atom() ) -&gt; string() | undefined
</div>
-<p>Get the value of a given HTTP request header. Valid values are:</p>
+<p>Get the value of a given HTTP request header. Valid values are strings or one of these atoms:</p>
<ul>
<li><code>accept</code></li>
<li><code>accept_language</code></li>
@@ -264,7 +264,7 @@ <h3>SimpleBridge</h3>
<li><code>x_forwarded_for</code></li>
</ul>
-<div class="code">
+<div class="code spec">
cookie( Key<span class="typevar">::string()</span> ) -&gt; string() | undefined
</div>
View
@@ -2,6 +2,19 @@
{% block api_content %}
<p>BossDB is a database abstraction layer used for querying and updating the database. Currently Tokyo Tyrant, Mnesia, MySQL, and PostgreSQL are supported.</p>
+
+<h2>Functions</h2>
+
+<p>Functions in the <code>boss_db</code> module include:</p>
+{% for function in functions %}
+{% if function.description_long %}
+<div class="code spec">
+ {{ function.function }}{% if function.typespec %}{{ function.typespec }}{% endif %}
+</div>
+<p>{{ function.description_long }}</p>
+{% endif %}
+{% endfor %}
+
<h2>Conditions and Comparison Operators</h2>
<p>The "find" and "count" functions each take a set of <code>Conditions</code>, which specify search criteria. Similar to Microsoft's <a href="http://msdn.microsoft.com/en-us/library/bb308959.aspx">LINQ</a>, the <code>Conditions</code> can use a special non-Erlang syntax for conciseness. This special syntax can't be compiled with Erlang's default compiler, so you'll have to let Boss compile your controllers which use it.</p>
@@ -169,16 +182,4 @@ <h2>Conditions and Comparison Operators</h2>
</div>
<p>The "key" attribute is less than or equal to Value.</p>
-
-<h2>Functions</h2>
-
-<p>Functions in the <code>boss_db</code> module include:</p>
-{% for function in functions %}
-{% if function.description_long %}
-<div class="code">
- {{ function.function }}{% if function.typespec %}{{ function.typespec }}{% endif %}
-</div>
-<p>{{ function.description_long }}</p>
-{% endif %}
-{% endfor %}
{% endblock %}
View
@@ -22,7 +22,7 @@ <h2>boss_mq API</h2>
{% for function in functions %}
{% if function.description_long %}
-<div class="code">
+<div class="code spec">
{{ function.function }}{% if function.typespec %}{{ function.typespec }}{% endif %}
</div>
<p>{{ function.description_long }}</p>
View
@@ -31,7 +31,7 @@ <h3>The <code>boss_news</code> module</h3>
<p>Functions for managing watches are:</p>
{% for function in functions %}
{% if function.description_long %}
-<div class="code">
+<div class="code spec">
{{ function.function }}{% if function.typespec %}{{ function.typespec }}{% endif %}
</div>
<p>{{ function.description_long }}</p>
View
@@ -38,7 +38,7 @@ <h2>Generated functions</h2>
{% for function in functions %}
{% ifnotequal function.function "trivial_counter" %}
<a name="{{ function.function }}"></a>
-<div class="code">
+<div class="code spec">
{{ function.function }}{% if function.typespec %}{{ function.typespec }}{% endif %}
</div>
<p>
@@ -57,13 +57,13 @@ <h2>Associations</h2>
<p>Special associations are generated from the following module attributes:</p>
-<div class="code">
+<div class="code spec">
<span class="attr">-belongs_to</span>(foo).
</div>
<p>Requires a matching <code>FooId</code> in the parameter list. Adds a function <code>foo()</code> which returns the BossRecord (of any type, usually <code>foo</code>) with ID equal to the current BossRecord's <code>FooId</code>.</p>
-<div class="code">
+<div class="code spec">
<span class="attr">-has</span>({bar, 1}).<br />
<span class="attr">-has</span>({bars, Count}). % Count &gt; 1<br />
<span class="attr">-has</span>({bars, many}). % alias for 1 million<br />
@@ -72,9 +72,11 @@ <h2>Associations</h2>
<p>Generates a function <code>bar()</code> or <code>bars()</code> which returns up to <code>Count</code> "bar" BossRecords with <code>FooId</code> equal to this BossRecord's ID. If Count is greater than 1, also creates <code>first_bar()</code> and <code>last_bar()</code> which return the first and last items in the association.</p>
<p>When <code>Count</code> is not equal to 1, <code>has</code> can also take a proplist of options as the third element in the tuple:</p>
-<div class="code">
+
+<div class="code spec">
<span class="attr">-has</span>({bars, many, [{sort_by, first_name}]}).</span>
</div>
+
<p>Valid options are:</p>
<ul>
<li><code>sort_by</code> - attribute to sort on. Defaults to 'id'</li>
@@ -93,7 +95,7 @@ <h2>Associations</h2>
<p>The two above attributes work similar to <code>belongs_to</code> and <code>has_many/has_one</code> in Rails.</p>
-<div class="code">
+<div class="code spec">
<span class="attr">-counter</span>(foo_counter).
</div>
View
@@ -17,7 +17,7 @@ <h2>boss_session</h2>
{% for function in session_functions %}
{% if function.description_long %}
-<div class="code">
+<div class="code spec">
{{ function.function }}{% if function.typespec %}{{ function.typespec }}{% endif %}
</div>
<p>{{ function.description_long }}</p>
@@ -44,7 +44,7 @@ <h2>Functions</h2>
{% for function in flash_functions %}
{% if function.description_long %}
-<div class="code">
+<div class="code spec">
{{ function.function }}{% if function.typespec %}{{ function.typespec }}{% endif %}
</div>
<p>{{ function.description_long }}</p>
View
@@ -33,7 +33,7 @@ <h3>boss_web_test</h3>
<p>Functions available in the <code>boss_web_test</code> module include:</p>
{% for function in test_functions %}
{% if function.description_long %}
-<div class="code">
+<div class="code spec">
{{ function.function }}{% if function.typespec %}{{ function.typespec }}{% endif %}
</div>
<p>{{ function.description_long }}</p>
@@ -45,7 +45,7 @@ <h3>boss_assert</h3>
<p>The <code>Assertions</code> list in a <code>boss_web_test</code> invocation will usually refer to functions in the <code>boss_assert</code> module. Available functions include:</p>
{% for function in assert_functions %}
{% if function.description_long %}
-<div class="code">
+<div class="code spec">
{{ function.function }}{% if function.typespec %}{{ function.typespec }}{% endif %}
</div>
<p>{{ function.description_long }}</p>
View
@@ -1,9 +1,11 @@
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <title>Chicago Boss: The Official API Reference</title>
</head>
<body>
- <link rel="stylesheet" type="text/css" href="/stylesheets/boss.css" />
+ <link rel="stylesheet" type="text/css" href="boss.css" />
+ <p><em><a href="/">Chicago Boss home</a></em></p>
<div style="text-align: center; font-style: italic;">
<p>The Chicago Boss API is mostly stable, but still might change before 1.0.</p>
View
@@ -27,7 +27,7 @@ div.quote {
font-style: italic;
}
div.code {
-padding: 10px; font-family: Courier New; background-color: black; color: white;
+padding: 10px; font-family: Courier New; background-color: #CCC; color: black;
}
div.code span.attr {
color: #00FF1A;
@@ -15,7 +15,7 @@
</div>
<p>Returns a BossRecord matching the <code>Id</code>. The <code>Id</code> must be unique across data types.</p>
<div class="code">
- find(Conn, Type<span class="typevar">::atom()</span>, Conditions, Max<span class="typevar">::integer()</span>, Skip<span class="typevar">::integer()</span>, Sort<span class="typevar">::atom()</span>, SortOrder) -&gt; [BossRecord]
+ find(Conn, Type<span class="typevar">::atom()</span>, Conditions, Max<span class="typevar">::integer()</span> | all, Skip<span class="typevar">::integer()</span>, Sort<span class="typevar">::atom()</span>, SortOrder) -&gt; [BossRecord]
</div>
<p>Queries for BossRecords. The <code>Conditions</code> are guaranteed to be in {Key, Operator, Value} format. See <a href="api-db.html">the BossDB API</a> for a list of query operators you need to support.</p>
<div class="code">
View
@@ -22,7 +22,7 @@
{template, "skel/boss.config", "{{dest}}/boss.config"}.
{template, "skel/src/mail/outgoing_mail_controller.erl", "{{dest}}/src/mail/{{appid}}_outgoing_mail_controller.erl"}.
{template, "skel/src/mail/incoming_mail_controller.erl", "{{dest}}/src/mail/{{appid}}_incoming_mail_controller.erl"}.
-{template, "skel/priv/init/news.erl", "{{dest}}/priv/init/{{appid}}_news.erl"}.
+{template, "skel/priv/init/news.erl", "{{dest}}/priv/init/{{appid}}_01_news.erl"}.
{file, "skel/priv/static/chicago-boss.png", "{{dest}}/priv/static/chicago-boss.png"}.
{file, "skel/priv/static/favicon.ico", "{{dest}}/priv/static/favicon.ico"}.
{file, "skel/priv/boss.routes", "{{dest}}/priv/{{appid}}.routes"}.
Oops, something went wrong.

0 comments on commit 4e620ad

Please sign in to comment.