teacup 0.0.1.pre

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.
Files changed (46) hide show
  1. data/.gitignore +3 -0
  2. data/Dofile +6 -0
  3. data/Gemfile +3 -0
  4. data/Gemfile.lock +26 -0
  5. data/README.md +151 -0
  6. data/Rakefile +39 -0
  7. data/lib/teacup.rb +41 -0
  8. data/lib/teacup/contributors.rb +7 -0
  9. data/lib/teacup/core_extensions/ui_view.rb +4 -0
  10. data/lib/teacup/core_extensions/ui_view_controller.rb +62 -0
  11. data/lib/teacup/layout.rb +207 -0
  12. data/lib/teacup/style_sheet.rb +195 -0
  13. data/lib/teacup/version.rb +5 -0
  14. data/lib/teacup/view.rb +123 -0
  15. data/pkg/teacup-0.0.0.gem +0 -0
  16. data/pkg/teacup-0.0.1.gem +0 -0
  17. data/proposals/other/README.md +45 -0
  18. data/proposals/other/app/config/application.rb +1 -0
  19. data/proposals/other/app/config/boot.rb +1 -0
  20. data/proposals/other/app/config/initializers/twitter.rb +7 -0
  21. data/proposals/other/app/controllers/events_controller.rb +28 -0
  22. data/proposals/other/app/controllers/venues_controller.rb +4 -0
  23. data/proposals/other/app/db/README.md +16 -0
  24. data/proposals/other/app/db/migrations/20120514201043_create_events.rb +9 -0
  25. data/proposals/other/app/db/migrations/20120514201044_add_price_to_events.rb +5 -0
  26. data/proposals/other/app/db/migrations/20120514201045_create_venues.rb +8 -0
  27. data/proposals/other/app/db/schema.rb +19 -0
  28. data/proposals/other/app/models/event.rb +14 -0
  29. data/proposals/other/app/models/venue.rb +3 -0
  30. data/proposals/other/app/views/events/edit.ipad.rb +8 -0
  31. data/proposals/other/app/views/events/edit.iphone.rb +7 -0
  32. data/proposals/other/app/views/events/show.ipad.rb +2 -0
  33. data/proposals/other/app/views/events/show.iphone.rb +3 -0
  34. data/samples/Hai/.gitignore +5 -0
  35. data/samples/Hai/Rakefile +12 -0
  36. data/samples/Hai/app/app_delegate.rb +9 -0
  37. data/samples/Hai/app/hai_controller.rb +9 -0
  38. data/samples/Hai/spec/main_spec.rb +9 -0
  39. data/samples/Hai/styles/ipad.rb +11 -0
  40. data/samples/Hai/styles/ipad_vertical.rb +3 -0
  41. data/samples/README.md +4 -0
  42. data/spec/spec_helper.rb +5 -0
  43. data/spec/teacup/contributions_spec.rb +13 -0
  44. data/spec/teacup/version_spec.rb +9 -0
  45. data/teacup.gemspec +27 -0
  46. metadata +130 -0
@@ -0,0 +1,3 @@
1
+ .DS_Store
2
+ .rspec
3
+ .sass-cache/
data/Dofile ADDED
@@ -0,0 +1,6 @@
1
+ require 'do_it'
2
+
3
+ tasks = DoIt.new do
4
+ todo 'Make a "nicer looking" sample app (or improve existing app).'
5
+ todo 'Extend wiki on Github.'
6
+ end
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
@@ -0,0 +1,26 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ teacup (0.0.1)
5
+ rake
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.1.3)
11
+ rake (0.9.2.2)
12
+ rspec (2.10.0)
13
+ rspec-core (~> 2.10.0)
14
+ rspec-expectations (~> 2.10.0)
15
+ rspec-mocks (~> 2.10.0)
16
+ rspec-core (2.10.1)
17
+ rspec-expectations (2.10.0)
18
+ diff-lcs (~> 1.1.3)
19
+ rspec-mocks (2.10.1)
20
+
21
+ PLATFORMS
22
+ ruby
23
+
24
+ DEPENDENCIES
25
+ rspec
26
+ teacup!
@@ -0,0 +1,151 @@
1
+ Teacup
2
+ ======
3
+
4
+ A community-driven DSL for creating user interfaces on the iphone.
5
+
6
+ By including the `Teacup` module, you can easily create layouts that adhere to
7
+ the [iOS user interface guidelines][iOS HIG], and it's an easy way to assign labels,
8
+ delegators, and datasources.
9
+
10
+ The goal is not to simply rename CocoaTouch method names, but to offer a
11
+ rubyesque (well, actually a rubymotion-esque) way to create an interface.
12
+
13
+ Using stylesheets and layouts, it makes coding an iOS app like designing a website with HTML and CSS.
14
+
15
+ **Check out a working sample app [here](https://github.com/rubymotion/teacup/tree/master/samples/Hai)!**
16
+
17
+ #### Installation
18
+
19
+ ```bash
20
+ $ git submodule add https://github.com:rubymotion/teacup vendor/teacup
21
+ ```
22
+
23
+ Then add the teacup library to your Rakefile:
24
+ ```
25
+ # Add libraries *before* your app so that you can access constants they define safely
26
+ #
27
+ dirs = ['vendor/teacup/lib', 'app']
28
+
29
+ # require all the directories in order.
30
+ app.files = dirs.map{|d| Dir.glob(File.join(app.project_dir, "#{d}/**/*.rb")) }.flatten
31
+ ```
32
+
33
+
34
+ #### Showdown
35
+
36
+ Regular
37
+
38
+ ```ruby
39
+ class SomeController < UIViewController
40
+ def viewDidLoad
41
+
42
+ @field = UITextField.new
43
+ @field.height = 50
44
+ @field.width = 200
45
+ view.addSubview(@field)
46
+
47
+ @search = UITextField.new
48
+ @search.height = 50
49
+ @search.width = 200
50
+ @search.placeholder = 'Find something...'
51
+ view.addSubview(@search)
52
+
53
+ true
54
+ end
55
+ end
56
+ ```
57
+
58
+ Teacup
59
+
60
+ ```ruby
61
+ # Stylesheet
62
+
63
+ Teacup::StyleSheet.new(:IPhone) do
64
+
65
+ style :field,
66
+ height: 50,
67
+ width: 200
68
+
69
+ style :search, extends: :field,
70
+ placeholder: 'Foo...'
71
+
72
+ end
73
+
74
+ # Controller
75
+
76
+ class SomeController < UIViewController
77
+
78
+ def viewDidLoad
79
+ view.addSubview(Teacup.style(:field, UITextField.new))
80
+ view.addSubview(Teacup.style(:search))
81
+ true
82
+ end
83
+
84
+ end
85
+ ```
86
+
87
+ Development
88
+ -----------
89
+
90
+ *Current version*: v0.0.0 (or see `lib/teacup/version.rb`)
91
+
92
+ *Last milestone*: Pick a name
93
+
94
+ *Next milestone*: Pick a DSL
95
+
96
+ teacup, being a community project, moves in "spurts" of decision making and
97
+ coding. Only the name — both the least and most important part :-) — is
98
+ decided.
99
+
100
+ We would love suggestions of any sort, and we're always free over at the `#teacuprb` channel on `irc.freenode.org`.
101
+
102
+
103
+ Ideas that proposals should keep in mind
104
+ ----------------------------------------
105
+
106
+ 1. output will conform, unless explicitly *disabled* to the [iOS HIG][]
107
+ 2. should provide a few useful layouts (see [readme for layout proposals](teacup/tree/master/proposals/layout)):
108
+ * basic: vertically arranged "things", or
109
+ * form: label/input combinations arranged in a table
110
+ * navbar: with ability to customize the buttons that get placed at the top
111
+ * tabbar: similar, but with the tabs at the bottom instead of nav at the top
112
+ * splitview: A splitview controller (for iPad Apps) with sane navigation defaults, nice loading webviews and JSON to populate the items in the popover menu
113
+
114
+ 3. layouts should have ways of placing things relative to edges, so placing a
115
+ label or nav at the "bottom" that spans the entire width should be *easy*.
116
+ (This means we'll need to check for ipad or iphone.)
117
+ 4. actions are either blocks, defined inline, or target/action combos (e.g.
118
+ `target: self, action: :my_method`)
119
+ 5. there should be a consistent "styling" language, preferably in a separate
120
+ file, something that could be handed to a designer. this is the BIG item!
121
+ 6. teacup should take a little `config` block for easy configuration
122
+ 7. Ideally, there should be some way to "inherit" styles in this language. So you can define a basic layout for all platforms and then tweak (see [readme for style proposals](teacup/tree/master/proposals/styles))
123
+
124
+ [iOS HIG]: http://developer.apple.com/library/ios/#DOCUMENTATION/UserExperience/Conceptual/MobileHIG/Introduction/Introduction.html
125
+
126
+ Bugs
127
+ ----
128
+
129
+ Please, do *not* hesitate to report any bugs you find with our source at the [Issues](https://github.com/rubymotion/teacup/issues) page.
130
+
131
+ Actual proposals
132
+ ----------------
133
+
134
+ 1. [stylesheet][Commune], by [ConradIrwin][]
135
+ 2. [teacup][teacup_colinta], by [colinta][]
136
+ 3. [style][style_by_beakr], by [Beakr][]
137
+ 3. [layout][layout_by_beakr], by [Beakr][]
138
+ 4. [layout][layout_by_farcaller], by [farcaller][]
139
+ 5. [hybrid][], by [colinta][]
140
+
141
+ [Commune]: https://github.com/colinta/teacup/blob/master/proposals/styles/stylesheet_by_conradirwin.rb
142
+ [teacup_colinta]: https://github.com/colinta/teacup/blob/master/proposals/styles/teacup_by_colinta.rb
143
+ [style_by_beakr]: https://github.com/colinta/teacup/blob/master/proposals/layout/beakr_improved.rb
144
+ [layout_by_beakr]: https://github.com/colinta/teacup/blob/master/proposals/styles/beakr_improved.rb
145
+ [layout_by_farcaller]: https://github.com/colinta/teacup/blob/master/proposals/styles/layout_by_farcaller.rb
146
+ [hybrid]: https://github.com/colinta/teacup/blob/master/proposals/layout/hybrid_style_and_layout_by_colinta.rb
147
+
148
+ [ConradIrwin]: https://github.com/ConradIrwin
149
+ [colinta]: https://github.com/colinta
150
+ [farcaller]: https://github.com/farcaller
151
+ [Beakr]: https://github.com/Beakr
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env rake
2
+
3
+ # Bundler gem tasks ftw
4
+ require 'bundler/gem_tasks'
5
+
6
+ require 'rspec/core/rake_task'
7
+ require File.expand_path '../lib/teacup/version.rb', __FILE__
8
+
9
+ # Default task
10
+ task :default => :spec # Run spec
11
+ task :v => :version # Alt
12
+
13
+ # - - - - - - - - - - - - - - - - - - -
14
+ # Tasks
15
+ # - - - - - - - - - - - - - - - - - - -
16
+
17
+ desc 'display Teacup\'s current version'
18
+ task(:version) { version }
19
+
20
+ desc 'diesplay list of contributors'
21
+ task(:contrib) { contrib }
22
+
23
+ desc 'run RSpec tests'
24
+ RSpec::Core::RakeTask.new
25
+
26
+ desc 'build and install the gem'
27
+ task(:prep) { system('rake build; rake install') }
28
+
29
+ # - - - - - - - - - - - - - - - - - - -
30
+ # Helpers
31
+ # - - - - - - - - - - - - - - - - - - -
32
+
33
+ def version
34
+ puts "Teacup #{Teacup::VERSION}"
35
+ end
36
+
37
+ def contrib
38
+ puts Teacup::CONTRIBUTORS
39
+ end
@@ -0,0 +1,41 @@
1
+ unless defined?(Motion::Project::Config)
2
+ raise "This file must be required within a RubyMotion project Rakefile."
3
+ end
4
+
5
+ # In order that we can prepend our files to the load path after the user has
6
+ # configured their app.files, we need to run code *after* the user has set up
7
+ # their app.
8
+ #
9
+ # Unfortunately, the canonical place to require rubygems is at the top of the
10
+ # file (while we could just add to the instructions "please `require 'teacup'`
11
+ # at the bottom, that would be odd, and no-one would read the instructions).
12
+ #
13
+ # To this end, we tweak the App setup function so that whenever setup is called,
14
+ # we configure teacup after that.
15
+ #
16
+ # This is not great though, as other gems may (following the instructions at
17
+ # http://reality.hk/posts/2012/05/22/create-gems-for-rubymotion/) also call
18
+ # setup...
19
+ #
20
+ # For sanity reasons, we therefore delete teacup requires from the load order
21
+ # and re-add them to the front every single time {setup} is called.
22
+ #
23
+ # TODO: We should send a patch to rubymotion that adds first-class support for
24
+ # app.gems. These could then be required *after* the user has finished running
25
+ # the setup block, so that they can just run setup properly.
26
+ #
27
+ class << Motion::Project::App
28
+
29
+ def setup_with_teacup
30
+ setup_without_teacup do |app|
31
+ yield app
32
+
33
+ dirs = %w(teacup teacup/core_extensions)
34
+ files = dirs.map{ |dir| Dir.glob("#{File.dirname(__FILE__)}/#{dir}/*.rb") }.flatten
35
+ app.files = files + (app.files - files)
36
+ end
37
+ end
38
+
39
+ alias setup_without_teacup setup
40
+ alias setup setup_with_teacup
41
+ end
@@ -0,0 +1,7 @@
1
+ module Teacup
2
+
3
+ # If you've made a contribution, add your name here in :' ... ' as a constant symbol.
4
+ # Please place names in aphabetical order.
5
+ CONTRIBUTORS = ['Chris Clarke', 'Colin Thomas-Arnold', 'Conrad Irwin', 'Roland Oth', 'Vladimir Pouzanov']
6
+
7
+ end
@@ -0,0 +1,4 @@
1
+ class UIView
2
+ include Teacup::Layout
3
+ include Teacup::View
4
+ end
@@ -0,0 +1,62 @@
1
+ class UIViewController
2
+ include Teacup::Layout
3
+
4
+ class << self
5
+ # Define the layout of a controller's view.
6
+ #
7
+ # This function is analogous to Teacup::Layout#layout, though it is
8
+ # designed so you can create an entire layout in a declarative manner in
9
+ # your controller.
10
+ #
11
+ # The hope is that his declarativeness will allow us to automatically
12
+ # deal with common iOS programming tasks (like releasing views when
13
+ # low-memory conditions occur) for you. This is still not implemented
14
+ # though.
15
+ #
16
+ # @param name The stylename for your controller's view.
17
+ #
18
+ # @param properties Any extra styles that you want to apply.
19
+ #
20
+ # @param &block The block in which you should define your layout.
21
+ # It will be instance_exec'd in the context of a
22
+ # controller instance.
23
+ #
24
+ # @example
25
+ # MyViewController < UIViewController
26
+ # layout :my_view do
27
+ # subview UILabel, xjad: "Test"
28
+ # subview UITextField, {
29
+ # frame: [[200, 200], [100, 100]]
30
+ # delegate: self
31
+ # }
32
+ # subview UIView, :shiny_thing) {
33
+ # subview UIView, :centre_of_shiny_thing
34
+ # }
35
+ # end
36
+ # end
37
+ #
38
+ def layout(stylename, properties={}, &block)
39
+ @layout_definition = [stylename, properties, block]
40
+ end
41
+
42
+ # Retreive the layout defined by {layout}
43
+ def layout_definition
44
+ @layout_definition
45
+ end
46
+ end
47
+
48
+ # Instantiate the layout from the class, and then call layoutDidLoad.
49
+ #
50
+ # If you want to use Teacup in your controller, please hook into layoutDidLoad,
51
+ # not viewDidLoad.
52
+ def viewDidLoad
53
+ if self.class.layout_definition
54
+ name, properties, block = self.class.layout_definition
55
+ layout(view, name, properties, &block)
56
+ end
57
+
58
+ layoutDidLoad
59
+ end
60
+
61
+ def layoutDidLoad; true; end
62
+ end
@@ -0,0 +1,207 @@
1
+ module Teacup
2
+ # Teacup::Layout defines a layout function that can be used to configure the
3
+ # layout of views in your application.
4
+ #
5
+ # It is included into UIView and UIViewController directly so these functions
6
+ # should be available when you need them.
7
+ #
8
+ # In order to use layout() in a UIViewController most effectively you will want
9
+ # to define a stylesheet method that returns a stylesheet.
10
+ #
11
+ # @example
12
+ # class MyViewController < UIViewController
13
+ # interface(:my_view) do
14
+ # layout UIImage, :logo
15
+ # end
16
+ #
17
+ # def stylesheet
18
+ # Teacup::Stylesheet::Logo
19
+ # end
20
+ # end
21
+ #
22
+ module Layout
23
+
24
+ # Alter the layout of a view
25
+ #
26
+ # @param instance The first parameter is the view that you want to
27
+ # layout.
28
+ #
29
+ # @param name The second parameter is optional, and is the
30
+ # stylename to apply to the element. When using
31
+ # stylesheets any properties defined in the
32
+ # current stylesheet (see {stylesheet}) for this
33
+ # element will be immediately applied.
34
+ #
35
+ # @param properties The third parameter is optional, and is a Hash
36
+ # of properties to apply to the view directly.
37
+ #
38
+ # @param &block If a block is passed, it is evaluated such that
39
+ # any calls to {subview} that occur within that
40
+ # block cause created subviews to be added to *this*
41
+ # view instead of to the top-level view.
42
+ #
43
+ # For example, to alter the width and height of a carousel:
44
+ #
45
+ # @example
46
+ # layout(carousel, width: 500, height: 100)
47
+ #
48
+ # Or to layout the carousel in the default style:
49
+ #
50
+ # @example
51
+ # layout(carousel, :default_carousel)
52
+ #
53
+ # You can also use this method with {subview}, for example to add a new
54
+ # image to a carousel:
55
+ #
56
+ # @example
57
+ # layout(carousel) {
58
+ # subview(UIImage, backgroundColor: UIColor.colorWithImagePattern(image)
59
+ # }
60
+ #
61
+ def layout(instance, name_or_properties, properties_or_nil=nil, &block)
62
+ if properties_or_nil
63
+ name = name_or_properties.to_sym
64
+ properties = properties_or_nil
65
+ elsif Hash === name_or_properties
66
+ name = nil
67
+ properties = name_or_properties
68
+ else
69
+ name = name_or_properties.to_sym
70
+ properties = nil
71
+ end
72
+
73
+ instance.stylesheet = stylesheet
74
+ instance.style(properties) if properties
75
+ instance.stylename = name if name
76
+
77
+ begin
78
+ superview_chain << instance
79
+ instance_exec(instance, &block) if block_given?
80
+ ensure
81
+ superview_chain.pop
82
+ end
83
+
84
+ instance
85
+ end
86
+
87
+ # Add a new subview to the view heirarchy.
88
+ #
89
+ # By default the subview will be added at the top level of the view heirarchy, though
90
+ # if this function is executed within a block passed to {layout} or {subview}, then this
91
+ # view will be added as a subview of the instance being layed out by the block.
92
+ #
93
+ # This is particularly useful when coupled with the {UIViewController.heirarchy} function
94
+ # that allows you to declare your view heirarchy.
95
+ #
96
+ # @param class_or_instance The UIView subclass (or instance thereof) that you want
97
+ # to add. If you pass a class, an instance will be created
98
+ # by calling {new}.
99
+ #
100
+ # @param *args Arguments to pass to {layout} to instruct teacup how to
101
+ # lay out the newly added subview.
102
+ #
103
+ # @param &block A block to execute with the current view context set to
104
+ # your new element, see {layout} for more details.
105
+ #
106
+ # @return instance The instance that was added to the view heirarchy.
107
+ #
108
+ # For example, to specify that a controller should contain some labels:
109
+ #
110
+ # @example
111
+ # MyViewController < UIViewController
112
+ # heirarchy(:my_view) do
113
+ # subview(UILabel, text: 'Test')
114
+ # subview(UILabel, :styled_label)
115
+ # end
116
+ # end
117
+ #
118
+ # If you need to add a new image at runtime, you can also do that:
119
+ #
120
+ # @example
121
+ # layout(carousel) {
122
+ # subview(UIImage, backgroundColor: UIColor.colorWithImagePattern(image)
123
+ # }
124
+ #
125
+ def subview(class_or_instance, *args, &block)
126
+ instance = Class === class_or_instance ? class_or_instance.new : class_or_instance
127
+
128
+ if Class === class_or_instance
129
+ unless class_or_instance <= UIView
130
+ raise "Expected subclass of UIView, got: #{class_or_instance.inspect}"
131
+ end
132
+ instance = class_or_instance.new
133
+ elsif UIView === class_or_instance
134
+ instance = class_or_instance
135
+ else
136
+ raise "Expected a UIView, got: #{class_or_instance.inspect}"
137
+ end
138
+
139
+ (superview_chain.last || top_level_view).addSubview(instance)
140
+
141
+ layout(instance, *args, &block)
142
+
143
+ instance
144
+ end
145
+
146
+ # Returns a stylesheet to use to style the contents of this controller's
147
+ # view.
148
+ #
149
+ # This method will be queried each time {restyle!} is called, and also
150
+ # implicitly # whenever Teacup needs to draw your layout (currently only at
151
+ # view load time).
152
+ #
153
+ # @return Teacup::Stylesheet
154
+ #
155
+ # @example
156
+ #
157
+ # def stylesheet
158
+ # if [UIDeviceOrientationLandscapeLeft,
159
+ # UIDeviceOrientationLandscapeRight].include?(UIDevice.currentDevice.orientation)
160
+ # Teacup::Stylesheet::IPad
161
+ # else
162
+ # Teacup::Stylesheet::IPadVertical
163
+ # end
164
+ # end
165
+ def stylesheet
166
+ nil
167
+ end
168
+
169
+ # Instruct teacup to reapply styles to your subviews
170
+ #
171
+ # You should call this whenever the return value of your stylesheet meethod
172
+ # would change,
173
+ #
174
+ # @example
175
+ # def willRotateToInterfaceOrientation(io, duration: duration)
176
+ # restyle!
177
+ # end
178
+ def restyle!
179
+ top_level_view.stylesheet = stylesheet
180
+ end
181
+
182
+ protected
183
+
184
+ # Get's the top-level UIView for this object.
185
+ #
186
+ # This can either be 'self' if the current object is in fact a UIView,
187
+ # or 'view' if it's a controller.
188
+ #
189
+ # @return UIView
190
+ def top_level_view
191
+ case self
192
+ when UIViewController
193
+ view
194
+ when UIView
195
+ self
196
+ end
197
+ end
198
+
199
+ # Get's the current stack of views in nested calls to layout.
200
+ #
201
+ # The view at the end of the stack is the one into which subviews
202
+ # are currently being attached.
203
+ def superview_chain
204
+ @superview_chain ||= []
205
+ end
206
+ end
207
+ end