marble 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.
Files changed (44) hide show
  1. data/.autotest +9 -0
  2. data/.gitignore +19 -0
  3. data/.travis.yml +6 -0
  4. data/.yardopts +3 -0
  5. data/Gemfile +2 -0
  6. data/Gemfile.lock +93 -0
  7. data/LICENSE +20 -0
  8. data/README.md +82 -0
  9. data/Rakefile +20 -0
  10. data/lib/marble.rb +274 -0
  11. data/lib/marble/rails_template_handler.rb +43 -0
  12. data/lib/marble/version.rb +4 -0
  13. data/marble.gemspec +29 -0
  14. data/test/rails/.autotest +5 -0
  15. data/test/rails/.gitignore +17 -0
  16. data/test/rails/Gemfile +11 -0
  17. data/test/rails/Gemfile.lock +87 -0
  18. data/test/rails/README.md +1 -0
  19. data/test/rails/Rakefile +4 -0
  20. data/test/rails/app/controllers/application_controller.rb +2 -0
  21. data/test/rails/app/controllers/test_controller.rb +6 -0
  22. data/test/rails/app/views/test/index.json.marble +4 -0
  23. data/test/rails/app/views/test/index.yaml.marble +4 -0
  24. data/test/rails/config.ru +4 -0
  25. data/test/rails/config/application.rb +15 -0
  26. data/test/rails/config/boot.rb +6 -0
  27. data/test/rails/config/environment.rb +5 -0
  28. data/test/rails/config/environments/development.rb +9 -0
  29. data/test/rails/config/environments/production.rb +9 -0
  30. data/test/rails/config/environments/test.rb +9 -0
  31. data/test/rails/config/initializers/secret_token.rb +1 -0
  32. data/test/rails/config/initializers/session_store.rb +1 -0
  33. data/test/rails/config/routes.rb +3 -0
  34. data/test/rails/public/404.html +26 -0
  35. data/test/rails/public/422.html +26 -0
  36. data/test/rails/public/500.html +26 -0
  37. data/test/rails/public/favicon.ico +0 -0
  38. data/test/rails/public/robots.txt +5 -0
  39. data/test/rails/script/rails +6 -0
  40. data/test/rails/test/integration/marble_test.rb +13 -0
  41. data/test/rails/test/test_helper.rb +3 -0
  42. data/test/test_helper.rb +7 -0
  43. data/test/test_marble.rb +127 -0
  44. metadata +204 -0
@@ -0,0 +1,9 @@
1
+ require 'bundler/setup'
2
+
3
+ Autotest.add_hook :initialize do |at|
4
+ at.testlib = 'minitest/unit'
5
+
6
+ %w{test/rails}.each do |exception|
7
+ at.add_exception(exception)
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ coverage
2
+ rdoc
3
+ pkg
4
+ test/tmp
5
+ test/version_tmp
6
+ tmp
7
+ pkg
8
+ *.gem
9
+ *.rbc
10
+ lib/bundler/man
11
+ spec/reports
12
+ .config
13
+ InstalledFiles
14
+ .bundle
15
+
16
+ # YARD artifacts
17
+ .yardoc
18
+ _yardoc
19
+ doc/
@@ -0,0 +1,6 @@
1
+ script: 'rake test'
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - ree
6
+ - jruby
@@ -0,0 +1,3 @@
1
+ --readme README.md
2
+ --markup markdown
3
+ --markup-provider maruku
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
@@ -0,0 +1,93 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ marble (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ ZenTest (4.5.0)
10
+ abstract (1.0.0)
11
+ actionmailer (3.0.5)
12
+ actionpack (= 3.0.5)
13
+ mail (~> 2.2.15)
14
+ actionpack (3.0.5)
15
+ activemodel (= 3.0.5)
16
+ activesupport (= 3.0.5)
17
+ builder (~> 2.1.2)
18
+ erubis (~> 2.6.6)
19
+ i18n (~> 0.4)
20
+ rack (~> 1.2.1)
21
+ rack-mount (~> 0.6.13)
22
+ rack-test (~> 0.5.7)
23
+ tzinfo (~> 0.3.23)
24
+ activemodel (3.0.5)
25
+ activesupport (= 3.0.5)
26
+ builder (~> 2.1.2)
27
+ i18n (~> 0.4)
28
+ activerecord (3.0.5)
29
+ activemodel (= 3.0.5)
30
+ activesupport (= 3.0.5)
31
+ arel (~> 2.0.2)
32
+ tzinfo (~> 0.3.23)
33
+ activeresource (3.0.5)
34
+ activemodel (= 3.0.5)
35
+ activesupport (= 3.0.5)
36
+ activesupport (3.0.5)
37
+ arel (2.0.9)
38
+ autotest (4.4.6)
39
+ ZenTest (>= 4.4.1)
40
+ builder (2.1.2)
41
+ erubis (2.6.6)
42
+ abstract (>= 1.0.0)
43
+ i18n (0.5.0)
44
+ json (1.5.1)
45
+ mail (2.2.15)
46
+ activesupport (>= 2.3.6)
47
+ i18n (>= 0.4.0)
48
+ mime-types (~> 1.16)
49
+ treetop (~> 1.4.8)
50
+ maruku (0.6.0)
51
+ syntax (>= 1.0.0)
52
+ mime-types (1.16)
53
+ minitest (2.1.0)
54
+ mocha (0.9.12)
55
+ polyglot (0.3.1)
56
+ rack (1.2.2)
57
+ rack-mount (0.6.13)
58
+ rack (>= 1.0.0)
59
+ rack-test (0.5.7)
60
+ rack (>= 1.0)
61
+ rails (3.0.5)
62
+ actionmailer (= 3.0.5)
63
+ actionpack (= 3.0.5)
64
+ activerecord (= 3.0.5)
65
+ activeresource (= 3.0.5)
66
+ activesupport (= 3.0.5)
67
+ bundler (~> 1.0)
68
+ railties (= 3.0.5)
69
+ railties (3.0.5)
70
+ actionpack (= 3.0.5)
71
+ activesupport (= 3.0.5)
72
+ rake (>= 0.8.7)
73
+ thor (~> 0.14.4)
74
+ rake (0.8.7)
75
+ syntax (1.0.0)
76
+ thor (0.14.6)
77
+ treetop (1.4.9)
78
+ polyglot (>= 0.3.1)
79
+ tzinfo (0.3.25)
80
+ yard (0.6.8)
81
+
82
+ PLATFORMS
83
+ ruby
84
+
85
+ DEPENDENCIES
86
+ autotest (~> 4.4)
87
+ json (~> 1.5)
88
+ marble!
89
+ maruku (~> 0.6)
90
+ minitest (~> 2.0)
91
+ mocha (~> 0.9)
92
+ rails (= 3.0.5)
93
+ yard (~> 0.6)
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Alexander Kern
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,82 @@
1
+ # marble [![StillMaintained Status](http://stillmaintained.com/CapnKernul/marble.png)](http://stillmaintained.com/CapnKernul/marble) [![Build Status](http://travis-ci.org/CapnKernul/marble.png)](http://travis-ci.org/CapnKernul/marble) #
2
+
3
+ Marble is a Ruby object builder. It makes generating complex Ruby objects, and
4
+ by extension JSON and YAML, much more readable. It's especially useful for Rails
5
+ JSON API templates.
6
+
7
+ ## Installation ##
8
+
9
+ Marble works both with and without Rails. Installation is as simple as adding
10
+ this line to your `Gemfile`:
11
+
12
+ gem 'marble'
13
+
14
+ If you'd like to use marble without bundler, you can also directly install the
15
+ gem:
16
+
17
+ gem install marble
18
+
19
+ ## Usage ##
20
+
21
+ First, require marble and create a builder.
22
+
23
+ require 'marble'
24
+ builder = Marble.new
25
+
26
+ This builder can build any Ruby object using the `#build` method. The yielded
27
+ value is the current builder:
28
+
29
+ builder.build do |m|
30
+ ['foo']
31
+ end # => ['foo']
32
+
33
+ However, this isn't very useful. The `#array` and `#hash` methods are far more
34
+ interesting. They allow you to build complex arrays and hashes in a minimal
35
+ amount of lines:
36
+
37
+ builder.array do |m|
38
+ m.item 'foo'
39
+ end # => ['foo']
40
+
41
+ builder.hash do |m|
42
+ m.foo 'bar'
43
+ end # => { 'foo' => 'bar' }
44
+
45
+ The returned value can be converted to JSON and YAML, giving you a really
46
+ concise way of creating JSON and YAML templates for API's.
47
+
48
+ See the `Marble` documentation for more details.
49
+
50
+ ## Usage with Rails ##
51
+
52
+ Marble provides a template handler for Rails. It supports object literal, JSON,
53
+ and YAML output formats. Name your view template with the extension `marble`.
54
+ The template creates a builder with the name `marble` for you to use. You can
55
+ rename it using the block parameter. For example, in order to generate a JSON
56
+ view:
57
+
58
+ # view_name.json.marble
59
+ marble.hash do |m|
60
+ m.foo 'bar'
61
+ end
62
+
63
+ # Renders: {"foo": "bar"}
64
+
65
+ See the `Marble::RailsTemplateHandler` documentation for more details.
66
+
67
+ ## Note on Patches/Pull Requests ##
68
+
69
+ * Fork the project.
70
+ * Make your feature addition or bug fix.
71
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
72
+ * Commit, but do not mess with the `Rakefile`. If you want to have your own version, that is fine but bump the version in a commit by itself in another branch so I can ignore it when I pull.
73
+ * Send me a pull request. Bonus points for git flow feature branches.
74
+
75
+ ## Resources ##
76
+
77
+ * [GitHub Repository](https://github.com/CapnKernul/marble)
78
+ * [Documentation](http://rubydoc.info/github/CapnKernul/marble)
79
+
80
+ ## License ##
81
+
82
+ Marble is licensed under the MIT License. See `LICENSE` for details.
@@ -0,0 +1,20 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ task :default => 'test:unit'
5
+
6
+ task :test => ['test:unit', 'test:rails']
7
+
8
+ require 'rake/testtask'
9
+ Rake::TestTask.new('test:unit') do |t|
10
+ t.ruby_opts += ['-rubygems']
11
+ t.libs << 'test'
12
+ t.pattern = 'test/test_*.rb'
13
+ end
14
+
15
+ task 'test:rails' do
16
+ sh <<-CMD
17
+ cd test/rails
18
+ rake
19
+ CMD
20
+ end
@@ -0,0 +1,274 @@
1
+ # Builder for Ruby objects. Provides a convenient interface for generating
2
+ # complex arrays and hashes.
3
+ #
4
+ # First instantiate a builder:
5
+ #
6
+ # builder = Marble.new
7
+ #
8
+ # Then, call either `#build`, `#array`, or `#hash` on the builder. You can use
9
+ # the yielded block parameter to give the builder a shorter name. I suggest `m`.
10
+ #
11
+ # builder.hash do |m|
12
+ # m.zombies 'oh my!'
13
+ # end
14
+ #
15
+ # The returned value is the built object.
16
+ class Marble
17
+ # Builds an arbitrary value.
18
+ #
19
+ # @example Build a simple value
20
+ # builder = Marble.new
21
+ # builder.build do |m|
22
+ # true
23
+ # end # => true
24
+ #
25
+ # @example Build a more complex value
26
+ # builder = Marble.new
27
+ # builder.build do |m|
28
+ # m.array do
29
+ # m.item 'foo'
30
+ # end
31
+ # end # => ['foo']
32
+ #
33
+ # @yield [builder] block to evaluate for the value
34
+ # @yieldparam builder [Marble] the current builder
35
+ # @return [Object] the built value
36
+ def build(&block)
37
+ value_structure(&block)
38
+ end
39
+
40
+ # Builds a hash.
41
+ #
42
+ # @example Build a simple hash
43
+ # builder = Marble.new
44
+ # builder.hash do |m|
45
+ # m.foo 'bar'
46
+ # m.baz 'quz'
47
+ # end # => { 'foo' => 'bar', 'baz' => 'quz' }
48
+ #
49
+ # @example Build nested hashes
50
+ # builder = Marble.new
51
+ # builder.hash do |m|
52
+ # m.foo :hash do
53
+ # m.bar 'baz'
54
+ # end
55
+ # end # => { 'foo' => { 'bar' => 'baz' } }
56
+ #
57
+ # @yield [builder] block to evaluate within the hash's context
58
+ # @yieldparam builder [Marble] the current builder
59
+ # @return [Hash] the built hash
60
+ def hash(&block)
61
+ insert_structure({}, &block)
62
+ end
63
+
64
+ # Builds an array.
65
+ #
66
+ # @example Build a simple array
67
+ # builder = Marble.new
68
+ # builder.array do |m|
69
+ # m.item 'foo'
70
+ # m.item 'bar'
71
+ # end # => ['foo', 'bar']
72
+ #
73
+ # @example Build nested arrays
74
+ # builder = Marble.new
75
+ # builder.array do |m|
76
+ # m.item :array do
77
+ # m.item 'foo'
78
+ # end
79
+ # end # => [['foo']]
80
+ #
81
+ # @yield [builder] block to evaluate within the array's context
82
+ # @yieldparam builder [Marble] the current builder
83
+ # @return [Array] the built array
84
+ def array(&block)
85
+ insert_structure([], &block)
86
+ end
87
+
88
+ # Calls `#pair` or `#key` depending on the context.
89
+ #
90
+ # When the current structure responds to `#push` (for example, in an array
91
+ # context), it calls `#item` ignoring the method name. This allows you to be
92
+ # more semantic when defining the items in an array. However, in most cases
93
+ # calling `#item` will suffice.
94
+ #
95
+ # When the current structure responds to `#[]=` (for example, in a hash
96
+ # context), it calls `#pair` with the stringified method name as the key.
97
+ # This, in general, is a more concise and preferred way than explicitly
98
+ # calling `#pair`.
99
+ #
100
+ # @example Build an array
101
+ # builder = Marble.new
102
+ # builder.array do |m|
103
+ # m.milk 'toast'
104
+ # end # => ['foo', 'bar']
105
+ #
106
+ # @example Build a hash
107
+ # builder = Marble.new
108
+ # builder.hash do |m|
109
+ # m.milk 'toast'
110
+ # end # => { 'milk' => 'toast' }
111
+ def method_missing(method, *args, &block)
112
+ if @current.respond_to?(:push)
113
+ item(*args, &block)
114
+ elsif @current.respond_to?(:[]=)
115
+ pair(method.to_s, *args, &block)
116
+ else
117
+ super
118
+ end
119
+ end
120
+
121
+ # Inserts an item into the current structure.
122
+ #
123
+ # Arrays are the most common structure into which you insert an item (any
124
+ # value). Items are inserted using `#push`, so if you'd like to duck-type an
125
+ # array for whatever reason, go ahead.
126
+ #
127
+ # You can provide values using either the second parameter or a block. If you
128
+ # provide a block, the block will be evaluated immediately.
129
+ #
130
+ # Blocks by default insert the value of the block into the item. However, you
131
+ # can optionally specify the structure type of the block as either `:array` or
132
+ # `:hash` to insert an array or hash structure. That means that these are all
133
+ # equivalent:
134
+ #
135
+ # m.array do
136
+ # m.item ['value']
137
+ # end
138
+ #
139
+ # m.array do
140
+ # m.item do
141
+ # ['value']
142
+ # end
143
+ # end
144
+ #
145
+ # m.array do
146
+ # m.item :hash do
147
+ # m.pair 'key', 'value'
148
+ # end
149
+ # end
150
+ #
151
+ # Choose the format that makes the most sense in a given context.
152
+ #
153
+ # @overload item(value)
154
+ # @param value [Object] the value to insert into the item
155
+ # @overload item()
156
+ # @yield [builder] block to evaluate for the item's value
157
+ # @yieldparam builder [Marble] the current builder
158
+ # @yieldreturn [Object] the value to insert into the item
159
+ # @overload item(structure_type)
160
+ # @param structure_type [:array, :hash] the block's structure type
161
+ # @yield [builder] block to evaluate for the item's value
162
+ # @yieldparam builder [Marble] the current builder
163
+ # @yieldreturn [Object] the value to insert into the item
164
+ def item(value_or_structure_type = nil, &block)
165
+ if block_given?
166
+ @current.push evaluate_structure(value_or_structure_type, &block)
167
+ else
168
+ @current.push value_or_structure_type
169
+ end
170
+ end
171
+
172
+ # Inserts a pair into the current structure.
173
+ #
174
+ # Hashes are the most common structure into which you insert a pair (key and
175
+ # value). Pairs are inserted using `#[]=`, so if you'd like to duck-type a
176
+ # hash for whatever reason, go ahead.
177
+ #
178
+ # You can provide values using either the second parameter or a block. If you
179
+ # provide a block, the block will be evaluated immediately.
180
+ #
181
+ # Blocks by default insert the value of the block into the pair. However, you
182
+ # can optionally specify the structure type of the block as either `:array` or
183
+ # `:hash` to insert an array or hash structure. That means that these are all
184
+ # equivalent:
185
+ #
186
+ # m.hash do
187
+ # m.pair 'key', ['value']
188
+ # end
189
+ #
190
+ # m.hash do
191
+ # m.pair 'key' do
192
+ # ['value']
193
+ # end
194
+ # end
195
+ #
196
+ # m.hash do
197
+ # m.pair 'key', :array do
198
+ # m.item 'value'
199
+ # end
200
+ # end
201
+ #
202
+ # Choose the format that makes the most sense in a given context.
203
+ #
204
+ # @overload pair(key, value)
205
+ # @param key [Object] the key to use for the pair
206
+ # @param value [Object] the value to insert into the pair
207
+ # @overload pair(key)
208
+ # @param key [Object] the key to use for the pair
209
+ # @yield [builder] block to evaluate for the pair's value
210
+ # @yieldparam builder [Marble] the current builder
211
+ # @yieldreturn [Object] the value to insert into the pair
212
+ # @overload pair(key, structure_type)
213
+ # @param key [Object] the key to use for the pair
214
+ # @param structure_type [:array, :hash] the block's structure type
215
+ # @yield [builder] block to evaluate for the pair's value
216
+ # @yieldparam builder [Marble] the current builder
217
+ # @yieldreturn [Object] the value to insert into the pair
218
+ def pair(key, value_or_structure_type = nil, &block)
219
+ if block_given?
220
+ @current[key] = evaluate_structure(value_or_structure_type, &block)
221
+ else
222
+ @current[key] = value_or_structure_type
223
+ end
224
+ end
225
+
226
+ private
227
+
228
+ # Inserts a value structure.
229
+ #
230
+ # This is really only used as an easy way to insert into the current structure
231
+ # to whatever the block evaluates.
232
+ #
233
+ # @yield [builder] block to evaluate for the value
234
+ # @yieldparam builder [Marble] the current builder
235
+ def value_structure(&block)
236
+ insert_structure(nil, &block)
237
+ end
238
+
239
+ # Inserts a structure into the current structure.
240
+ #
241
+ # @param structure [Object] the new structure to insert
242
+ # @yield [builder] block to evaluate for the value
243
+ # @yieldparam builder [Marble] the current builder
244
+ def insert_structure(structure)
245
+ if block_given?
246
+ parent = @current
247
+ @current = structure
248
+ value = yield(self)
249
+ @current = parent
250
+ end
251
+
252
+ structure || value
253
+ end
254
+
255
+ # Convenience method for inserting the correct structure type based on a
256
+ # symbol.
257
+ #
258
+ # @param type [Symbol] the structure type
259
+ # @yield [builder] block to evaluate for the value
260
+ # @yieldparam builder [Marble] the current builder
261
+ def evaluate_structure(type, &block)
262
+ case type
263
+ when :hash then hash(&block)
264
+ when :array then array(&block)
265
+ else value_structure(&block)
266
+ end
267
+ end
268
+ end
269
+
270
+ require 'marble/version'
271
+
272
+ if defined? ActionView::Template
273
+ require 'marble/rails_template_handler'
274
+ end