in_json 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,24 @@
1
+ source 'http://rubygems.org'
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem 'activesupport', '>= 2.3.5'
5
+
6
+ gem 'activerecord', '>= 2.3.8', :require => 'active_record'
7
+ gem 'activesupport', '>= 2.3.8', :require => 'active_support'
8
+ gem 'json'
9
+
10
+ # Add dependencies to develop your gem here.
11
+ # Include everything needed to run rake, tests, features, etc.
12
+ group :development do
13
+ gem 'rspec', '~> 2.3.0'
14
+ gem 'yard', '~> 0.6.0'
15
+ gem 'bundler', '~> 1.0.0'
16
+ gem 'jeweler', '~> 1.5.2'
17
+ gem 'rcov', '>= 0'
18
+ gem 'reek', '~> 1.2.8'
19
+ gem 'roodi', '~> 2.1.0'
20
+ gem 'autotest'
21
+ gem 'sqlite3'
22
+ gem 'rspec-rails'
23
+ gem 'database_cleaner'
24
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,64 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ ZenTest (4.5.0)
5
+ activerecord (2.3.11)
6
+ activesupport (= 2.3.11)
7
+ activesupport (2.3.11)
8
+ autotest (4.4.6)
9
+ ZenTest (>= 4.4.1)
10
+ database_cleaner (0.6.4)
11
+ diff-lcs (1.1.2)
12
+ git (1.2.5)
13
+ jeweler (1.5.2)
14
+ bundler (~> 1.0.0)
15
+ git (>= 1.2.5)
16
+ rake
17
+ json (1.5.1)
18
+ rack (1.2.1)
19
+ rake (0.8.7)
20
+ rcov (0.9.9)
21
+ reek (1.2.8)
22
+ ruby2ruby (~> 1.2)
23
+ ruby_parser (~> 2.0)
24
+ sexp_processor (~> 3.0)
25
+ roodi (2.1.0)
26
+ ruby_parser
27
+ rspec (2.3.0)
28
+ rspec-core (~> 2.3.0)
29
+ rspec-expectations (~> 2.3.0)
30
+ rspec-mocks (~> 2.3.0)
31
+ rspec-core (2.3.1)
32
+ rspec-expectations (2.3.0)
33
+ diff-lcs (~> 1.1.2)
34
+ rspec-mocks (2.3.0)
35
+ rspec-rails (1.3.2)
36
+ rack (>= 1.0.0)
37
+ rspec (>= 1.3.0)
38
+ ruby2ruby (1.2.5)
39
+ ruby_parser (~> 2.0)
40
+ sexp_processor (~> 3.0)
41
+ ruby_parser (2.0.6)
42
+ sexp_processor (~> 3.0)
43
+ sexp_processor (3.0.5)
44
+ sqlite3 (1.3.3)
45
+ yard (0.6.4)
46
+
47
+ PLATFORMS
48
+ ruby
49
+
50
+ DEPENDENCIES
51
+ activerecord (>= 2.3.8)
52
+ activesupport (>= 2.3.8)
53
+ autotest
54
+ bundler (~> 1.0.0)
55
+ database_cleaner
56
+ jeweler (~> 1.5.2)
57
+ json
58
+ rcov
59
+ reek (~> 1.2.8)
60
+ roodi (~> 2.1.0)
61
+ rspec (~> 2.3.0)
62
+ rspec-rails
63
+ sqlite3
64
+ yard (~> 0.6.0)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Henry Hsu
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.
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = in_json
2
+
3
+ JSON serialization for Rails. Straight-forward attributes. Only serialize what you want. Optimally obeys eager-loaded associations
4
+
5
+ == Contributing to in_json
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
9
+ * Fork the project
10
+ * Start a feature/bugfix branch
11
+ * Commit and push until you are happy with your contribution
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2011 Henry Hsu. See LICENSE.txt for
18
+ further details.
19
+
data/Rakefile ADDED
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "in_json"
16
+ gem.homepage = "http://github.com/hsume2/in_json"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{Optimally straight-forward JSON serialization for Rails}
19
+ gem.description = %Q{JSON serialization for Rails. Straight-forward attributes. Only serialize what you want. Optimally obeys eager-loaded associations}
20
+ gem.email = "henry.hsu@photomugs.com"
21
+ gem.authors = ["Henry Hsu"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rspec/core'
30
+ require 'rspec/core/rake_task'
31
+ RSpec::Core::RakeTask.new(:spec) do |spec|
32
+ spec.pattern = FileList['spec/**/*_spec.rb']
33
+ end
34
+
35
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
36
+ spec.pattern = 'spec/**/*_spec.rb'
37
+ spec.rcov = true
38
+ spec.rcov_opts = %w(--exclude gems)
39
+ end
40
+
41
+ require 'reek/rake/task'
42
+ Reek::Rake::Task.new do |t|
43
+ t.fail_on_error = true
44
+ t.verbose = false
45
+ t.source_files = 'lib/**/*.rb'
46
+ end
47
+
48
+ require 'roodi'
49
+ require 'roodi_task'
50
+ RoodiTask.new do |t|
51
+ t.verbose = false
52
+ end
53
+
54
+ task :default => :spec
55
+
56
+ require 'yard'
57
+ YARD::Rake::YardocTask.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/in_json.gemspec ADDED
@@ -0,0 +1,96 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{in_json}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Henry Hsu"]
12
+ s.date = %q{2011-03-10}
13
+ s.description = %q{JSON serialization for Rails. Straight-forward attributes. Only serialize what you want. Optimally obeys eager-loaded associations}
14
+ s.email = %q{henry.hsu@photomugs.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE.txt",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "in_json.gemspec",
29
+ "lib/in_json.rb",
30
+ "lib/in_json/ext/array.rb",
31
+ "spec/in_json_spec.rb",
32
+ "spec/spec_helper.rb"
33
+ ]
34
+ s.homepage = %q{http://github.com/hsume2/in_json}
35
+ s.licenses = ["MIT"]
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = %q{1.3.7}
38
+ s.summary = %q{Optimally straight-forward JSON serialization for Rails}
39
+ s.test_files = [
40
+ "spec/in_json_spec.rb",
41
+ "spec/spec_helper.rb"
42
+ ]
43
+
44
+ if s.respond_to? :specification_version then
45
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
46
+ s.specification_version = 3
47
+
48
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
49
+ s.add_runtime_dependency(%q<activerecord>, [">= 2.3.8"])
50
+ s.add_runtime_dependency(%q<activesupport>, [">= 2.3.8"])
51
+ s.add_runtime_dependency(%q<json>, [">= 0"])
52
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
53
+ s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
54
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
55
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
56
+ s.add_development_dependency(%q<rcov>, [">= 0"])
57
+ s.add_development_dependency(%q<reek>, ["~> 1.2.8"])
58
+ s.add_development_dependency(%q<roodi>, ["~> 2.1.0"])
59
+ s.add_development_dependency(%q<autotest>, [">= 0"])
60
+ s.add_development_dependency(%q<sqlite3>, [">= 0"])
61
+ s.add_development_dependency(%q<rspec-rails>, [">= 0"])
62
+ s.add_development_dependency(%q<database_cleaner>, [">= 0"])
63
+ else
64
+ s.add_dependency(%q<activerecord>, [">= 2.3.8"])
65
+ s.add_dependency(%q<activesupport>, [">= 2.3.8"])
66
+ s.add_dependency(%q<json>, [">= 0"])
67
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
68
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
69
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
70
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
71
+ s.add_dependency(%q<rcov>, [">= 0"])
72
+ s.add_dependency(%q<reek>, ["~> 1.2.8"])
73
+ s.add_dependency(%q<roodi>, ["~> 2.1.0"])
74
+ s.add_dependency(%q<autotest>, [">= 0"])
75
+ s.add_dependency(%q<sqlite3>, [">= 0"])
76
+ s.add_dependency(%q<rspec-rails>, [">= 0"])
77
+ s.add_dependency(%q<database_cleaner>, [">= 0"])
78
+ end
79
+ else
80
+ s.add_dependency(%q<activerecord>, [">= 2.3.8"])
81
+ s.add_dependency(%q<activesupport>, [">= 2.3.8"])
82
+ s.add_dependency(%q<json>, [">= 0"])
83
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
84
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
85
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
86
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
87
+ s.add_dependency(%q<rcov>, [">= 0"])
88
+ s.add_dependency(%q<reek>, ["~> 1.2.8"])
89
+ s.add_dependency(%q<roodi>, ["~> 2.1.0"])
90
+ s.add_dependency(%q<autotest>, [">= 0"])
91
+ s.add_dependency(%q<sqlite3>, [">= 0"])
92
+ s.add_dependency(%q<rspec-rails>, [">= 0"])
93
+ s.add_dependency(%q<database_cleaner>, [">= 0"])
94
+ end
95
+ end
96
+
@@ -0,0 +1,17 @@
1
+ module InJson
2
+ module ArrayExt
3
+ def self.included(base)
4
+ base.send :include, InstanceMethods
5
+ end
6
+
7
+ module InstanceMethods
8
+ def in_json(name = :default, overrule_definition = nil)
9
+ map { |entry| entry.respond_to?(:in_json) ? entry.in_json(name, overrule_definition) : entry }
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ Array.class_eval do
16
+ include InJson::ArrayExt
17
+ end
data/lib/in_json.rb ADDED
@@ -0,0 +1,96 @@
1
+ require 'in_json/ext/array'
2
+
3
+ module InJson
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ base.send :include, InstanceMethods
7
+ end
8
+
9
+ def self.with(name = :default, &block)
10
+ begin
11
+ Thread.current[:in_json_definition] = name
12
+ yield
13
+ ensure
14
+ Thread.current[:in_json_definition] = nil
15
+ end
16
+ end
17
+
18
+ # A {Definition} is a proxy class primarily for evaluating {InJson} blocks into a {Hash} definition.
19
+ #
20
+ # class Post
21
+ # in_json do
22
+ # name
23
+ # email
24
+ # end # => {:email=>nil, :name=>nil}
25
+ #
26
+ # in_json(:with_posts_and_comments_named) do
27
+ # posts do
28
+ # title
29
+ # comments :only_approved
30
+ # end
31
+ # end # => {:posts=>{:title=>nil, :comments=>:only_approved}}
32
+ # end
33
+ class Definition
34
+ def initialize
35
+ @hash = {}
36
+ end
37
+
38
+ # Stores any method calls as {Hash} keys
39
+ # @return [Hash] the evaluated definition
40
+ def method_missing(method, *args, &block)
41
+ method = method.to_s.sub(/^_/, '').to_sym if method.to_s =~ /^_.*/
42
+ @hash[method] = block_given? ? Definition.new.instance_eval(&block) : args.first
43
+ @hash
44
+ end
45
+ end
46
+
47
+ module ClassMethods
48
+ # Defines an {InJson} definition that can be used to convert an object to JSON format {InJson::InstanceMethods#in_json}
49
+ # @param [Symbol] name the name of the definition
50
+ # @yield a block of definitions
51
+ def in_json(name = :default, &block)
52
+ definitions = read_inheritable_attribute(:in_json_definitions) || {}
53
+
54
+ definitions[name] = Definition.new.instance_eval(&block)
55
+
56
+ write_inheritable_attribute :in_json_definitions, definitions
57
+ end
58
+ end
59
+
60
+ module InstanceMethods
61
+ # Returns a Hash that can be used as this object in JSON format
62
+ # @param [Symbol] name the {InJson} definition to evaluate
63
+ # @param [Symbol, Hash, nil] injected_definition a named {InJson} definition, a full Hash definition, or nil
64
+ # @return [Hash] the JSON-ready Hash
65
+ def in_json(name = :default, injected_definition = nil)
66
+ definition = in_json_definition(name, injected_definition)
67
+ attrs = attributes.freeze.symbolize_keys
68
+ return attrs unless definition
69
+ definition.inject({}) do |result, attr_dfn|
70
+ attr, definition = attr_dfn
71
+
72
+ result_at = attrs.has_key?(attr) ? attrs[attr] : send(attr)
73
+ result_at = result_at.in_json(name, definition) if result_at.respond_to?(:in_json) && !result_at.kind_of?(Class)
74
+
75
+ result[attr] = result_at
76
+ result
77
+ end
78
+ end
79
+ alias_method :as_json, :in_json
80
+
81
+ protected
82
+
83
+ def in_json_definition(name, injected_definition)
84
+ definitions = self.class.read_inheritable_attribute(:in_json_definitions)
85
+ if Thread.current[:in_json_definition] || injected_definition.kind_of?(Symbol)
86
+ definitions && (definitions[Thread.current[:in_json_definition]] || definitions[injected_definition])
87
+ elsif injected_definition.kind_of?(Hash)
88
+ injected_definition
89
+ elsif definitions
90
+ definitions[name]
91
+ end || (definitions && definitions[:default])
92
+ end
93
+ end
94
+ end
95
+
96
+ ActiveRecord::Base.class_eval { include InJson }
@@ -0,0 +1,307 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ class User < ActiveRecord::Base
4
+ has_many :posts
5
+ has_many :blog_posts
6
+
7
+ in_json do
8
+ name
9
+ email
10
+ end
11
+
12
+ in_json(:with_reserved) do
13
+ _id
14
+ _type
15
+ end
16
+
17
+ in_json(:with_post_count) do
18
+ name
19
+ email
20
+ post_count
21
+ end
22
+
23
+ in_json(:with_posts) do
24
+ post_count
25
+ posts
26
+ end
27
+
28
+ in_json(:with_posts_nested) do
29
+ posts do
30
+ title
31
+ content
32
+ end
33
+ end
34
+
35
+ in_json(:with_posts_named) do
36
+ posts :only_content
37
+ end
38
+
39
+ in_json(:with_posts_and_comments) do
40
+ posts do
41
+ title
42
+ comments do
43
+ content
44
+ end
45
+ end
46
+ end
47
+
48
+ in_json(:with_posts_and_comments_named) do
49
+ posts do
50
+ title
51
+ comments :only_approved
52
+ end
53
+ end
54
+
55
+ in_json(:with_posts_and_comments_missing) do
56
+ posts do
57
+ title
58
+ comments :always_missing
59
+ end
60
+ end
61
+
62
+ def post_count
63
+ self.posts.count
64
+ end
65
+ end
66
+
67
+ class Post < ActiveRecord::Base
68
+ belongs_to :user
69
+ has_many :comments
70
+ has_many :reviews
71
+
72
+ in_json do
73
+ title
74
+ end
75
+
76
+ in_json(:only_content) do
77
+ content
78
+ end
79
+
80
+ in_json(:with_user) do
81
+ user
82
+ end
83
+
84
+ in_json(:with_reviews) do
85
+ reviews do
86
+ score
87
+ end
88
+ end
89
+ end
90
+
91
+ class BlogPost < Post
92
+ end
93
+
94
+ class Comment < ActiveRecord::Base
95
+ belongs_to :post
96
+
97
+ in_json do
98
+ content
99
+ end
100
+
101
+ in_json(:only_approved) do
102
+ approved
103
+ end
104
+ end
105
+
106
+ class Review < ActiveRecord::Base
107
+ belongs_to :post
108
+ end
109
+
110
+ describe InJson do
111
+ before do
112
+ @user = User.create(:name => "John User", :email => "john@example.com")
113
+ @post = @user.posts.create(:title => "Hello World!", :content => "Welcome to my blog.")
114
+ @blog_post = @user.blog_posts.create(:title => "Hello World!", :content => "Welcome to my blog post.")
115
+ @comment = @post.comments.create(:content => "Great blog!", :approved => true)
116
+ end
117
+
118
+ it "should return model in json (default)" do
119
+ @user.in_json.should == {
120
+ :name => 'John User',
121
+ :email => 'john@example.com'
122
+ }
123
+ end
124
+
125
+ it "should return model in json without definition (default)" do
126
+ @user.in_json(:missing_def).should == {
127
+ :name => 'John User',
128
+ :email => 'john@example.com'
129
+ }
130
+ end
131
+
132
+ it "should return model in json with reserved methods" do
133
+ @user.in_json(:with_reserved).should == {
134
+ :id => @user.id,
135
+ :type => User
136
+ }
137
+ end
138
+
139
+ it "should return model in json with post count" do
140
+ @user.in_json(:with_post_count).should == {
141
+ :name => 'John User',
142
+ :email => 'john@example.com',
143
+ :post_count => 2
144
+ }
145
+ end
146
+
147
+ it "should return model in json with posts" do
148
+ @user.in_json(:with_posts).should == {
149
+ :post_count => 2,
150
+ :posts => [
151
+ { :title => 'Hello World!' },
152
+ { :title => 'Hello World!' }
153
+ ]
154
+ }
155
+ end
156
+
157
+ it "should return model in json with posts and nested definition" do
158
+ @user.in_json(:with_posts_nested).should == {
159
+ :posts => [
160
+ { :title => 'Hello World!', :content => 'Welcome to my blog.' },
161
+ { :title => 'Hello World!', :content => 'Welcome to my blog post.' }
162
+ ]
163
+ }
164
+ end
165
+
166
+ it "should return model in json with posts and named definition" do
167
+ @user.in_json(:with_posts_named).should == {
168
+ :posts => [
169
+ { :content => 'Welcome to my blog.' },
170
+ { :content => 'Welcome to my blog post.' }
171
+ ]
172
+ }
173
+ end
174
+
175
+ it "should return model in json with posts and comments" do
176
+ @user.in_json(:with_posts_and_comments).should == {
177
+ :posts => [
178
+ { :title => 'Hello World!', :comments=>[{:content=>"Great blog!"}] },
179
+ { :title => 'Hello World!', :comments=>[] }
180
+ ]
181
+ }
182
+ end
183
+
184
+ it "should return model in json with posts and comments named" do
185
+ @user.in_json(:with_posts_and_comments_named).should == {
186
+ :posts => [
187
+ { :title => 'Hello World!', :comments=>[{:approved=>true}] },
188
+ { :title => 'Hello World!', :comments=>[] }
189
+ ]
190
+ }
191
+ end
192
+
193
+ it "should return model in json with posts and comments missing" do
194
+ @user.in_json(:with_posts_and_comments_missing).should == {
195
+ :posts => [
196
+ { :title => 'Hello World!', :comments=>[{:content=>"Great blog!"}] },
197
+ { :title => 'Hello World!', :comments=>[] }
198
+ ]
199
+ }
200
+ end
201
+
202
+ it "should use eager-loaded associations" do
203
+ lambda { @user = User.find(:first, :include => { :posts => :comments }) }.should have_queries(3)
204
+
205
+ lambda {
206
+ @user.in_json(:with_posts_and_comments).should == {
207
+ :posts => [
208
+ { :title => 'Hello World!', :comments=>[{:content=>"Great blog!"}] },
209
+ { :title => 'Hello World!', :comments=>[] }
210
+ ]
211
+ }
212
+ }.should have_queries(0)
213
+ end
214
+
215
+ it "should use eager-loaded associations on collection" do
216
+ user = User.create(:name => "John User", :email => "john@example.com")
217
+ post = user.posts.create(:title => "Hello World!", :content => "Welcome to my blog.")
218
+
219
+ lambda { @users = User.find(:all, :include => { :posts => :comments }) }.should have_queries(3)
220
+ lambda {
221
+ @users.in_json(:with_posts_and_comments).should == [{
222
+ :posts => [
223
+ { :title => 'Hello World!', :comments=>[{:content=>"Great blog!"}] },
224
+ { :title => 'Hello World!', :comments=>[] }
225
+ ]
226
+ },
227
+ {
228
+ :posts => [
229
+ { :title => 'Hello World!', :comments=>[] }
230
+ ]
231
+ }]
232
+ }.should have_queries(0)
233
+ end
234
+
235
+ it "should return model as json" do
236
+ @user_hash = JSON.parse(@user.to_json)
237
+ @user_hash['name'].should == 'John User'
238
+ @user_hash['email'].should == 'john@example.com'
239
+ end
240
+
241
+ it "should return collection as json" do
242
+ user = User.create(:name => "User John", :email => "example@john.com")
243
+ post = user.posts.create(:title => "Hello World!", :content => "Welcome to my blog.")
244
+ @users = User.find(:all, :include => { :posts => :comments })
245
+
246
+ @users_hash = JSON.parse(@users.to_json)
247
+ @users_hash.tap do |h|
248
+ h.size.should == 2
249
+ h[0].tap do |u|
250
+ u['name'].should == 'John User'
251
+ u['email'].should == 'john@example.com'
252
+ end
253
+ h[1].tap do |u|
254
+ u['name'].should == 'User John'
255
+ u['email'].should == 'example@john.com'
256
+ end
257
+ end
258
+ end
259
+
260
+ it "should return model in json when without definition and default" do
261
+ @review = @blog_post.reviews.create(:score => 5)
262
+ @review.in_json.should == {
263
+ :id => @review.id,
264
+ :post_id => @blog_post.id,
265
+ :score => 5
266
+ }
267
+ end
268
+
269
+ it "should return model in json when nested without default" do
270
+ @review = @blog_post.reviews.create(:score => 5)
271
+ @blog_post.in_json(:with_reviews).should == {
272
+ :reviews => [
273
+ { :score => 5 }
274
+ ]
275
+ }
276
+ end
277
+
278
+ it "should return model in json with post count via Thread" do
279
+ InJson.with(:with_post_count) do
280
+ @user.in_json.should == {
281
+ :name => 'John User',
282
+ :email => 'john@example.com',
283
+ :post_count => 2
284
+ }
285
+ end
286
+ end
287
+
288
+ it "should return model in json with posts and named definition via Thread" do
289
+ InJson.with(:with_posts_named) do
290
+ @user.in_json.should == {
291
+ :posts => [
292
+ { :content => 'Welcome to my blog.' },
293
+ { :content => 'Welcome to my blog post.' }
294
+ ]
295
+ }
296
+ end
297
+ end
298
+
299
+ it "should return model with user" do
300
+ @post.in_json(:with_user).should == {
301
+ :user => {
302
+ :name => 'John User',
303
+ :email => 'john@example.com'
304
+ }
305
+ }
306
+ end
307
+ end
@@ -0,0 +1,98 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+ Bundler.require(:default)
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'rspec'
8
+ require 'in_json'
9
+
10
+ # Requires supporting files with custom matchers and macros, etc,
11
+ # in ./support/ and its subdirectories.
12
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
13
+
14
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
15
+
16
+ [:users, :posts, :comments].each do |table|
17
+ ActiveRecord::Base.connection.drop_table table rescue nil
18
+ end
19
+
20
+ ActiveRecord::Base.connection.create_table :users do |t|
21
+ t.string :name
22
+ t.string :email
23
+ end
24
+
25
+ ActiveRecord::Base.connection.create_table :posts do |t|
26
+ t.string :title
27
+ t.text :content
28
+ t.integer :user_id
29
+ t.string :type
30
+ end
31
+
32
+ ActiveRecord::Base.connection.create_table :comments do |t|
33
+ t.text :content
34
+ t.boolean :approved
35
+ t.integer :post_id
36
+ end
37
+
38
+ ActiveRecord::Base.connection.create_table :reviews do |t|
39
+ t.integer :score
40
+ t.integer :post_id
41
+ end
42
+
43
+ ActiveRecord::Base.connection.class.class_eval do
44
+ IGNORED_SQL = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /SHOW FIELDS/]
45
+
46
+ def execute_with_query_record(sql, name = nil, &block)
47
+ $queries_executed ||= []
48
+ $queries_executed << sql unless IGNORED_SQL.any? { |r| sql =~ r }
49
+ execute_without_query_record(sql, name, &block)
50
+ end
51
+
52
+ alias_method_chain :execute, :query_record
53
+ end
54
+
55
+ module ActiveRecordQueriesMatcher
56
+ class HaveQueries
57
+ def initialize(num)
58
+ @num = num
59
+ end
60
+
61
+ def matches?(target)
62
+ begin
63
+ $queries_executed = []
64
+ target.call
65
+ @num == $queries_executed.size
66
+ ensure
67
+ %w{ BEGIN COMMIT }.each { |x| $queries_executed.delete(x) }
68
+ end
69
+ end
70
+
71
+ def failure_message_for_should
72
+ "#{$queries_executed.size} instead of #{@num} queries were executed.#{$queries_executed.size == 0 ? '' : "\nQueries:\n#{$queries_executed.join("\n")}"}"
73
+ end
74
+ end
75
+
76
+ def have_queries(num = 1)
77
+ HaveQueries.new(num)
78
+ end
79
+ end
80
+
81
+ require 'database_cleaner'
82
+
83
+ RSpec.configure do |config|
84
+ config.include ActiveRecordQueriesMatcher
85
+
86
+ config.before(:suite) do
87
+ DatabaseCleaner.strategy = :transaction
88
+ DatabaseCleaner.clean_with(:truncation)
89
+ end
90
+
91
+ config.before(:each) do
92
+ DatabaseCleaner.start
93
+ end
94
+
95
+ config.after(:each) do
96
+ DatabaseCleaner.clean
97
+ end
98
+ end
metadata ADDED
@@ -0,0 +1,292 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: in_json
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Henry Hsu
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-10 00:00:00 -08:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ prerelease: false
23
+ type: :runtime
24
+ name: activerecord
25
+ version_requirements: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 19
31
+ segments:
32
+ - 2
33
+ - 3
34
+ - 8
35
+ version: 2.3.8
36
+ requirement: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ prerelease: false
39
+ type: :runtime
40
+ name: activesupport
41
+ version_requirements: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ hash: 19
47
+ segments:
48
+ - 2
49
+ - 3
50
+ - 8
51
+ version: 2.3.8
52
+ requirement: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ prerelease: false
55
+ type: :runtime
56
+ name: json
57
+ version_requirements: &id003 !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 3
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ requirement: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ prerelease: false
69
+ type: :development
70
+ name: rspec
71
+ version_requirements: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 2
79
+ - 3
80
+ - 0
81
+ version: 2.3.0
82
+ requirement: *id004
83
+ - !ruby/object:Gem::Dependency
84
+ prerelease: false
85
+ type: :development
86
+ name: yard
87
+ version_requirements: &id005 !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ~>
91
+ - !ruby/object:Gem::Version
92
+ hash: 7
93
+ segments:
94
+ - 0
95
+ - 6
96
+ - 0
97
+ version: 0.6.0
98
+ requirement: *id005
99
+ - !ruby/object:Gem::Dependency
100
+ prerelease: false
101
+ type: :development
102
+ name: bundler
103
+ version_requirements: &id006 !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ~>
107
+ - !ruby/object:Gem::Version
108
+ hash: 23
109
+ segments:
110
+ - 1
111
+ - 0
112
+ - 0
113
+ version: 1.0.0
114
+ requirement: *id006
115
+ - !ruby/object:Gem::Dependency
116
+ prerelease: false
117
+ type: :development
118
+ name: jeweler
119
+ version_requirements: &id007 !ruby/object:Gem::Requirement
120
+ none: false
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ hash: 7
125
+ segments:
126
+ - 1
127
+ - 5
128
+ - 2
129
+ version: 1.5.2
130
+ requirement: *id007
131
+ - !ruby/object:Gem::Dependency
132
+ prerelease: false
133
+ type: :development
134
+ name: rcov
135
+ version_requirements: &id008 !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ hash: 3
141
+ segments:
142
+ - 0
143
+ version: "0"
144
+ requirement: *id008
145
+ - !ruby/object:Gem::Dependency
146
+ prerelease: false
147
+ type: :development
148
+ name: reek
149
+ version_requirements: &id009 !ruby/object:Gem::Requirement
150
+ none: false
151
+ requirements:
152
+ - - ~>
153
+ - !ruby/object:Gem::Version
154
+ hash: 15
155
+ segments:
156
+ - 1
157
+ - 2
158
+ - 8
159
+ version: 1.2.8
160
+ requirement: *id009
161
+ - !ruby/object:Gem::Dependency
162
+ prerelease: false
163
+ type: :development
164
+ name: roodi
165
+ version_requirements: &id010 !ruby/object:Gem::Requirement
166
+ none: false
167
+ requirements:
168
+ - - ~>
169
+ - !ruby/object:Gem::Version
170
+ hash: 11
171
+ segments:
172
+ - 2
173
+ - 1
174
+ - 0
175
+ version: 2.1.0
176
+ requirement: *id010
177
+ - !ruby/object:Gem::Dependency
178
+ prerelease: false
179
+ type: :development
180
+ name: autotest
181
+ version_requirements: &id011 !ruby/object:Gem::Requirement
182
+ none: false
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ hash: 3
187
+ segments:
188
+ - 0
189
+ version: "0"
190
+ requirement: *id011
191
+ - !ruby/object:Gem::Dependency
192
+ prerelease: false
193
+ type: :development
194
+ name: sqlite3
195
+ version_requirements: &id012 !ruby/object:Gem::Requirement
196
+ none: false
197
+ requirements:
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ hash: 3
201
+ segments:
202
+ - 0
203
+ version: "0"
204
+ requirement: *id012
205
+ - !ruby/object:Gem::Dependency
206
+ prerelease: false
207
+ type: :development
208
+ name: rspec-rails
209
+ version_requirements: &id013 !ruby/object:Gem::Requirement
210
+ none: false
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ hash: 3
215
+ segments:
216
+ - 0
217
+ version: "0"
218
+ requirement: *id013
219
+ - !ruby/object:Gem::Dependency
220
+ prerelease: false
221
+ type: :development
222
+ name: database_cleaner
223
+ version_requirements: &id014 !ruby/object:Gem::Requirement
224
+ none: false
225
+ requirements:
226
+ - - ">="
227
+ - !ruby/object:Gem::Version
228
+ hash: 3
229
+ segments:
230
+ - 0
231
+ version: "0"
232
+ requirement: *id014
233
+ description: JSON serialization for Rails. Straight-forward attributes. Only serialize what you want. Optimally obeys eager-loaded associations
234
+ email: henry.hsu@photomugs.com
235
+ executables: []
236
+
237
+ extensions: []
238
+
239
+ extra_rdoc_files:
240
+ - LICENSE.txt
241
+ - README.rdoc
242
+ files:
243
+ - .document
244
+ - .rspec
245
+ - Gemfile
246
+ - Gemfile.lock
247
+ - LICENSE.txt
248
+ - README.rdoc
249
+ - Rakefile
250
+ - VERSION
251
+ - in_json.gemspec
252
+ - lib/in_json.rb
253
+ - lib/in_json/ext/array.rb
254
+ - spec/in_json_spec.rb
255
+ - spec/spec_helper.rb
256
+ has_rdoc: true
257
+ homepage: http://github.com/hsume2/in_json
258
+ licenses:
259
+ - MIT
260
+ post_install_message:
261
+ rdoc_options: []
262
+
263
+ require_paths:
264
+ - lib
265
+ required_ruby_version: !ruby/object:Gem::Requirement
266
+ none: false
267
+ requirements:
268
+ - - ">="
269
+ - !ruby/object:Gem::Version
270
+ hash: 3
271
+ segments:
272
+ - 0
273
+ version: "0"
274
+ required_rubygems_version: !ruby/object:Gem::Requirement
275
+ none: false
276
+ requirements:
277
+ - - ">="
278
+ - !ruby/object:Gem::Version
279
+ hash: 3
280
+ segments:
281
+ - 0
282
+ version: "0"
283
+ requirements: []
284
+
285
+ rubyforge_project:
286
+ rubygems_version: 1.3.7
287
+ signing_key:
288
+ specification_version: 3
289
+ summary: Optimally straight-forward JSON serialization for Rails
290
+ test_files:
291
+ - spec/in_json_spec.rb
292
+ - spec/spec_helper.rb