motion-kit-events 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +119 -0
- data/lib/motion-kit-events/layout.rb +45 -0
- data/lib/motion-kit-events/version.rb +5 -0
- data/lib/motion-kit-events.rb +23 -0
- data/spec/ios/events_spec.rb +16 -0
- metadata +79 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1dff0c162d7aa79745f3688409745e9a096b5af0
|
4
|
+
data.tar.gz: 9e8bc6302c39eb7c3fa2ee82a2f2e3c42221fda7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4bfcebe914349985e9d232779761fa8d579058daf73f76d1912a54d6ee1e5a8174524cc9d6bea87dd3a90c6f1ffb2c679530b5d86d63dc45d7cd67b1be32bfda
|
7
|
+
data.tar.gz: 8ce463671100d3867c42658b3f10def5192a461eb6df7cb9e3873ffcd863273b157eee5597ab4d741b76ff56b6e811e054b5756cca37102406a7e370fe0b6ee7
|
data/README.md
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
MotionKit::Events
|
2
|
+
--------
|
3
|
+
|
4
|
+
In an effort to encourage even MORE separation of concerns in your Controllers
|
5
|
+
and Layouts, the `motion-kit-events` gem provides a very way to emit generic
|
6
|
+
events from your layout that you can respond to in your controller.
|
7
|
+
|
8
|
+
## LoginController
|
9
|
+
|
10
|
+
An example of a UIViewController using MotionKit::Events:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
class LoginController < UIViewController
|
14
|
+
|
15
|
+
def loadView
|
16
|
+
@layout = LoginLayout.new
|
17
|
+
self.view = @layout.view
|
18
|
+
|
19
|
+
@layout.on :login do |username, password|
|
20
|
+
@layout.pause_ui
|
21
|
+
# send login info to the API (I would recommend using a separate class
|
22
|
+
# to handle the API conversation, e.g. a LoginStorage class).
|
23
|
+
storage.login(username, password) do |user, errors|
|
24
|
+
handle_login(user, errors)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def storage
|
30
|
+
@storage ||= LoginStorage.new
|
31
|
+
end
|
32
|
+
|
33
|
+
def handle_login(user, errors)
|
34
|
+
# ...
|
35
|
+
@layout.resume_ui
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
Before we go on to show the `LoginLayout`, consider for a second how *easy* it
|
42
|
+
would be to write specs for a controller like this. We don't need to test the
|
43
|
+
UI (that will be done in isolation, using the `LoginLayout`) and our controller
|
44
|
+
doesn't directly send any *requests*, so we can assign it (in our specs) a
|
45
|
+
`TestLoginLayout` class as the storage, which can imitate the behaviors we are
|
46
|
+
interested in. We should also use a fake layout class in there, too.
|
47
|
+
|
48
|
+
TL;DR: we can test just the behavior of the controller. When it receives a
|
49
|
+
`:login` event, it should send a `login` request to its storage, and handle
|
50
|
+
`user` or `errors`.
|
51
|
+
|
52
|
+
|
53
|
+
## LoginLayout
|
54
|
+
|
55
|
+
We send the `:login` event along with the username and password when the user
|
56
|
+
presses the login button or presses "Return" from the password field. This is
|
57
|
+
all code that would normally be in the UIViewController. The tight coupling of
|
58
|
+
the UIViewController and the UI is very common in iOS apps, but there is much to
|
59
|
+
be gained be decoupling these roles. The Controller can focus on the *movement*
|
60
|
+
of the user.
|
61
|
+
|
62
|
+
The user starts out in a "logging in" state. Until they submit credentials, the
|
63
|
+
controller need not be interested in what the UI is doing to accomodate this
|
64
|
+
procedure. It just cares about when the user is *done*, and it pauses the UI.
|
65
|
+
|
66
|
+
When the login attempt is complete, the controller tells the UI what state to go
|
67
|
+
in next, either resuming the UI if an error occurred, or just dimissing the
|
68
|
+
controller and passing along the successful login info.
|
69
|
+
|
70
|
+
If you look at the code provided by MotionKit::Events you'll be happy to see
|
71
|
+
that it is a *tiny* little gem. But using it to decouple your UI from your
|
72
|
+
controller can provide a huge long term benefit in terms of keeping your code
|
73
|
+
maintainable!
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
class LoginLayout < MK::Layout
|
77
|
+
|
78
|
+
def layout
|
79
|
+
add UITextField, :username_field do
|
80
|
+
delegate self
|
81
|
+
end
|
82
|
+
|
83
|
+
add UITextField, :password_field do
|
84
|
+
delegate self
|
85
|
+
end
|
86
|
+
|
87
|
+
add UIButton, :login_button do
|
88
|
+
on :touch do
|
89
|
+
trigger_login
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def trigger_login
|
95
|
+
# send the username and password to our controller
|
96
|
+
trigger :login, get(:username_field).text.to_s, get(:password_field).text.to_s
|
97
|
+
end
|
98
|
+
|
99
|
+
def textFieldShouldReturn(field)
|
100
|
+
if field == get(:password_field)
|
101
|
+
trigger_login
|
102
|
+
else
|
103
|
+
get(:password_field).becomeFirstResponder
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
```
|
109
|
+
|
110
|
+
The sample app (most of the code is in [app/ios/login/][login]) includes a working
|
111
|
+
version of this example.
|
112
|
+
|
113
|
+
[login]: https://github.com/rubymotion/motion-kit-events/tree/master/app/ios/login/
|
114
|
+
|
115
|
+
###### Note
|
116
|
+
|
117
|
+
The example and specs all require SugarCube to run; this is just because I
|
118
|
+
wanted to have the specs make sure that the `on` method (used in so many gems)
|
119
|
+
behaves the way you would expect it to.
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# @requires MotionKit::BaseLayout
|
2
|
+
module MotionKit
|
3
|
+
class BaseLayout
|
4
|
+
|
5
|
+
def motion_kit_event_handlers
|
6
|
+
@motion_kit_event_handlers ||= {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def on(*args, &handler)
|
10
|
+
if @context || @assign_root
|
11
|
+
apply_with_target(:on, *args, &handler)
|
12
|
+
else
|
13
|
+
event = args.first
|
14
|
+
unless event
|
15
|
+
raise ArgumentError.new('`event` is a required argument to Layout#on')
|
16
|
+
end
|
17
|
+
motion_kit_event_handlers[event] ||= []
|
18
|
+
motion_kit_event_handlers[event] << handler.weak!
|
19
|
+
|
20
|
+
self
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def trigger(*args, &handler)
|
25
|
+
if @context
|
26
|
+
apply(:trigger, *args, &handler)
|
27
|
+
else
|
28
|
+
event = args.first
|
29
|
+
unless event
|
30
|
+
raise ArgumentError.new('`event` is a required argument to Layout#on')
|
31
|
+
end
|
32
|
+
|
33
|
+
if motion_kit_event_handlers[event]
|
34
|
+
motion_kit_event_handlers[event].each do |handler|
|
35
|
+
handler.call(args[1..-1])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
self
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
unless defined?(Motion::Project::Config)
|
2
|
+
raise "The MotionKit::Events gem must be required within a RubyMotion project Rakefile."
|
3
|
+
end
|
4
|
+
|
5
|
+
|
6
|
+
require 'motion-kit'
|
7
|
+
require 'dbt'
|
8
|
+
|
9
|
+
|
10
|
+
Motion::Project::App.setup do |app|
|
11
|
+
lib = File.join(File.dirname(__FILE__), 'motion-kit-events')
|
12
|
+
|
13
|
+
# scans app.files until it finds app/ (the default)
|
14
|
+
# if found, it inserts just before those files, otherwise it will insert to
|
15
|
+
# the end of the list
|
16
|
+
insert_point = app.files.find_index { |file| file =~ /^(?:\.\/)?app\// } || 0
|
17
|
+
|
18
|
+
Dir.glob(File.join(lib, '**/*.rb')).reverse.each do |file|
|
19
|
+
app.files.insert(insert_point, file)
|
20
|
+
end
|
21
|
+
|
22
|
+
DBT.analyze(app)
|
23
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
describe 'MotionKit::Events' do
|
2
|
+
tests EventsController
|
3
|
+
|
4
|
+
it 'should respond to the layout trigger' do
|
5
|
+
controller.success.should.not == true
|
6
|
+
controller.layout.trigger(:test)
|
7
|
+
controller.success.should == true
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should respond to the test button' do
|
11
|
+
controller.success.should.not == true
|
12
|
+
controller.test_button.trigger(:touch)
|
13
|
+
controller.success.should == true
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: motion-kit-events
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Colin T.A. Gray
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: motion-kit
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dbt
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: |
|
42
|
+
Use +on+ and +trigger+ to send generic events from the layout to the controller.
|
43
|
+
email:
|
44
|
+
- colinta@gmail.com
|
45
|
+
executables: []
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- lib/motion-kit-events/layout.rb
|
50
|
+
- lib/motion-kit-events/version.rb
|
51
|
+
- lib/motion-kit-events.rb
|
52
|
+
- README.md
|
53
|
+
- spec/ios/events_spec.rb
|
54
|
+
homepage: https://github.com/rubymotion/motion-kit-events
|
55
|
+
licenses:
|
56
|
+
- BSD
|
57
|
+
metadata: {}
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements: []
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 2.0.3
|
75
|
+
signing_key:
|
76
|
+
specification_version: 4
|
77
|
+
summary: Adds simple event methods to MotionKit::Layout classes.
|
78
|
+
test_files:
|
79
|
+
- spec/ios/events_spec.rb
|