README.md in elevate-0.5.0 vs README.md in elevate-0.6.0
- old
+ new
@@ -1,24 +1,23 @@
Elevate
======
Stop scattering your domain logic across your view controller. Consolidate it to a single conceptual unit with Elevate.
-[](https://codeclimate.com/github/mattgreen/elevate) [](https://travis-ci.org/mattgreen/elevate)
+[](https://codeclimate.com/github/mattgreen/elevate) [](https://travis-ci.org/mattgreen/elevate) [](http://badge.fury.io/rb/elevate)
Example
-------
```ruby
@login_task = async username: username.text, password: password.text do
+ # This block runs on a background thread.
task do
- # This block runs on a background thread.
- #
- # The @username and @password instance variables correspond to the args
- # passed into async. API is a thin wrapper class over Elevate::HTTP,
- # which blocks until the request returns, yet can be interrupted.
- credentials = API.login(@username, @password)
+ # @username and @password correspond to the Hash keys provided to async.
+ args = { username: @username, password: @password }
+
+ credentials = Elevate::HTTP.post(LOGIN_URL, args)
if credentials
UserRegistration.store(credentials.username, credentials.token)
end
# Anything yielded from this block is passed to on_update
@@ -55,35 +54,33 @@
end
```
Background
-----------
-Many iOS apps have fairly simple domain logic that is obscured by several programming 'taxes':
+Many iOS/OS X apps have fairly simple domain logic that is obscured by several programming 'taxes':
* UI management
* asynchronous network requests
* I/O-heavy operations, such as storing large datasets to disk
These are necessary to ensure a good user experience, but they splinter your domain logic (that is, what your application does) through your view controller. Gross.
-Elevate is a mini task queue for your iOS app, much like Resque or Sidekiq. Rather than defining part of an operation to run on the UI thread, and a CPU-intensive portion on a background thread, Elevate is designed so you run the *entire* operation in the background, and receive notifications when it starts and finishes. This has a nice side effect of consolidating all the interaction for a particular task to one place. The UI code is cleanly isolated from the non-UI code. When your tasks become complex, you can elect to extract them out to a service object.
+Elevate is a mini task queue for your app, much like Resque or Sidekiq. Rather than defining part of an operation to run on the UI thread, and a CPU-intensive portion on a background thread, Elevate is designed so you run the *entire* operation in the background, and receive notifications at various times. This has a nice side effect of consolidating all the interaction for a particular task to one place. The UI code is cleanly isolated from the non-UI code. When your tasks become complex, you can elect to extract them out to a service object.
-In a sense, Elevate is almost a control-flow library: it bends the rules of iOS development a bit to ensure that the unique value your application provides is as clear as possible. This is most apparent with how Elevate handles network I/O: it provides a blocking HTTP client built from NSURLRequest for use within your tasks. This lets you write your tasks in a simple, blocking manner, while letting Elevate handle concerns relating to cancellation, and errors.
+In a sense, Elevate is almost a control-flow library: it bends the rules of app development a bit to ensure that the unique value your application provides is as clear as possible.
-Features
+Documentation
--------
+- [Tutorial](https://github.com/mattgreen/elevate/wiki/Tutorial) - start here
-* Small, beautiful DSL for describing your tasks
-* Actor-style concurrency
-* Simplifies asynchronous HTTP requests when used with Elevate::HTTP
-* Built atop of NSOperationQueue
+- [Wiki](https://github.com/mattgreen/elevate/wiki)
Installation
------------
Update your Gemfile:
- gem "elevate", "~> 0.5.0"
+ gem "elevate", "~> 0.6.0"
Bundle:
$ bundle install
@@ -96,25 +93,19 @@
class ArtistsSearchViewController < UIViewController
include Elevate
```
Launch an async task with the `async` method:
-
-* Pass all the data the task needs to operate (such as credentials or search terms) in to the `async` method.
-* Define a block that contains a `task` block. The `task` block should contain all of your non-UI code. It will be run on a background thread. Any data passed into the `async` method will be available as instance variables, keyed by the provided hash key.
-* Optionally:
- * Define an `on_start` block to be run when the task starts
- * Define an `on_finish` block to be run when the task finishes
- * Define an `on_update` block to be called any time the task calls yield (useful for relaying status information back during long operations)
-
-All of the `on_` blocks are called on the UI thread. `on_start` is guaranteed to precede `on_update` and `on_finish`.
-
```ruby
@track_task = async artist: searchBar.text do
task do
- artist = API.track(@artist)
+ response = Elevate::HTTP.get("http://example.com/artists", query: { artist: @artist })
+
+ artist = Artist.from_hash(response)
ArtistDB.update(artist)
+
+ response["name"]
end
on_start do
SVProgressHUD.showWithStatus("Adding...")
end
@@ -123,16 +114,39 @@
SVProgressHUD.dismiss
end
end
```
-To cancel a task (like when the view controller is being dismissed), call `cancel` on the task returned by the `async` method. This causes a `CancelledError` to be raised within the task itself, which is handled by the Elevate runtime. This also prevents any callbacks you have defined from running.
+If you might need to cancel the task later, call `cancel` on the object returned by `async`:
+```ruby
+@track_task.cancel
+```
-**NOTE: Within tasks, do not access the UI or containing view controller! It is extremely dangerous to do so. You must pass data into the `async` method to use it safely.**
+Timeouts
+--------
+Elevate 0.6.0 includes support for timeouts. Timeouts are declared using the `timeout` method within the `async` block. They start when an operation is queued, and automatically abort the task when the duration passes. If the task takes longer than the specified duration, the `on_timeout` callback is run.
-To Do
------
-* Need ability to set timeout for tasks
+Example:
+
+```ruby
+async do
+ timeout 0.1
+
+ task do
+ Elevate::HTTP.get("http://example.com/")
+ end
+
+ on_timeout do
+ puts 'timed out'
+ end
+
+ on_finish do |result, exception|
+ puts 'completed!'
+ end
+end
+
+
+```
Caveats
---------
* Must use Elevate's HTTP client instead of other iOS networking libs