the_grid 1.0.7

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.
data/spec/api_spec.rb ADDED
@@ -0,0 +1,58 @@
1
+ require "spec_helper"
2
+
3
+ describe TheGrid::Api do
4
+ subject{ TheGrid::Api.new(relation) }
5
+
6
+ let(:child_relation) { double("Child Relation").as_null_object }
7
+ let(:relation) { double("Relation", :reflections => { :child_relation => child_relation }).as_null_object }
8
+ let(:commands) { lambda{ |name| ::TheGrid::Api::Command.find(name) } }
9
+
10
+ context "when run single command" do
11
+ let(:options) {{ :field => "title", :order => "desc" }}
12
+ let(:cmd_name) { :sort }
13
+
14
+ after(:each) { subject.run_command!(cmd_name, options) }
15
+
16
+ it "run specified command" do
17
+ commands[cmd_name].should_receive(:execute_on).with(subject.relation, options)
18
+ end
19
+
20
+ it "should be prepared by command instance" do
21
+ commands[cmd_name].should_receive(:contextualize).with(subject.relation, options).and_return({})
22
+ end
23
+
24
+ it "run delegated command on specified target" do
25
+ subject.delegate(cmd_name => :child_relation)
26
+ commands[cmd_name].should_receive(:execute_on).with(child_relation, options)
27
+ end
28
+ end
29
+
30
+ context "when run few commands" do
31
+ let(:params) {{ :cmd => [:sort, :search, :batch_update], :field => "title", :query => "test" }}
32
+ before(:each) { subject.stub(:run_command!) }
33
+ after(:each) { subject.compose!(params) }
34
+
35
+ it "skip batch commands" do
36
+ commands[:batch_update].should_not_receive(:execute_on)
37
+ end
38
+
39
+ it "run specified commands" do
40
+ subject.should_receive(:run_command!).with(:sort, params)
41
+ subject.should_receive(:run_command!).with(:search, params)
42
+ end
43
+
44
+ it "adds paginate command by default" do
45
+ subject.should_receive(:run_command!).with(:paginate, params)
46
+ end
47
+
48
+ it "doesn't add paginate command if per_page equals false" do
49
+ params[:per_page] = false
50
+ subject.should_not_receive(:run_command!).with(:paginate, params)
51
+ end
52
+
53
+ it "delegates specified commands" do
54
+ params[:delegate] = {:sort => child_relation}
55
+ subject.should_receive(:delegate).with(params[:delegate])
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,182 @@
1
+ require 'spec_helper'
2
+
3
+ describe TheGrid::Builder::Context do
4
+ subject{ TheGrid::Builder::Context }
5
+
6
+ let(:parent_scope) { double(:dsl => Proc.new{ column :title }) }
7
+ let(:options) {{ :per_page => 25, :scope => parent_scope }}
8
+
9
+ context "by default" do
10
+ it "has hidden id column" do
11
+ build_context.columns[:id].should have_key(:hidden)
12
+ end
13
+
14
+ it "stores specified options" do
15
+ build_context.options[:per_page].should eql options[:per_page]
16
+ end
17
+
18
+ it "requires block" do
19
+ expect{ subject.new(options) }.to raise_error ArgumentError
20
+ end
21
+
22
+ it "respects parent context" do
23
+ parent_scope.should_receive(:article_path)
24
+ build_context{ url article_path }
25
+ end
26
+
27
+ it "responds to assemble" do
28
+ build_context.should respond_to(:assemble).with(1).argument
29
+ end
30
+ end
31
+
32
+ context "DSL" do
33
+ it "defines columns" do
34
+ build_context{ column :name; column :url }.columns.keys.should include(:name, :url)
35
+ end
36
+
37
+ it "defines column specific options" do
38
+ columns = build_context{ column :name, :test => true, :value => 5 }.columns
39
+ columns[:name].values_at(:test, :value).should eql [true, 5]
40
+ end
41
+
42
+ it "marks columns as featurable" do
43
+ columns = build_context{ searchable_columns :name, :text }.columns
44
+ columns.slice(:name, :text).should be_all{ |k, v| v[:searchable] == true }
45
+ end
46
+
47
+ it "stores featureable columns in options" do
48
+ build_context{ searchable_columns :name, :text }.options[:searchable_columns].should eql [:name, :text]
49
+ end
50
+
51
+ it "accepts single option's values" do
52
+ options = build_context{ title "test"; email "test@example.com" }.options
53
+ options.values_at(:title, :email).should eql %w{ test test@example.com }
54
+ end
55
+
56
+ it "accepts multiple option's values" do
57
+ build_context{ my :name, :age, :pan }.options[:my].should eql [:name, :age, :pan]
58
+ end
59
+
60
+ it "accepts block as column generator" do
61
+ build_context{ column(:name){ "test" } }.columns[:name][:as].should respond_to(:call)
62
+ end
63
+
64
+ it "accepts method_name as column generator" do
65
+ build_context{ column :name, :as => :title}.columns[:name][:as].should eql :title
66
+ end
67
+
68
+ it "defines nested scope" do
69
+ context = build_context{ scope_for(:articles, &dsl) }
70
+ context.columns[:articles][:as].should be_kind_of subject
71
+ end
72
+
73
+ it "defines nested scope with specified name" do
74
+ context = build_context{ scope_for(:articles, :as => :children, &dsl) }
75
+ context.columns[:children][:as].should be_kind_of subject
76
+ end
77
+ end
78
+
79
+ context "when collects visible columns" do
80
+ let(:parent_scope){ double(:dsl => Proc.new{ column :title; column :name, :hidden => true }) }
81
+
82
+ it "returns only visible columns" do
83
+ build_context(&parent_scope.dsl).visible_columns.keys.should eql [:title]
84
+ end
85
+
86
+ it "respects visible columns of nested scopes" do
87
+ build_context{ scope_for(:children, &dsl) }.visible_columns[:children].keys.should eql [:title]
88
+ end
89
+ end
90
+
91
+ context "when assembles" do
92
+ let(:fields) {{ :title => "item", :id => 5, :live? => false, :short_details => "details" }}
93
+ let(:records) {[ double(fields), double(fields.merge :live? => true) ]}
94
+
95
+ context "records" do
96
+ subject { context.assemble(records) }
97
+ let(:context) { build_plane_context }
98
+
99
+ it { should be_kind_of Array }
100
+ it { should have(records.size).items }
101
+ it { should be_all{ |r| r.kind_of? Hash } }
102
+ it { should be_all{ |r| r.keys == context.columns.keys }}
103
+ end
104
+
105
+ context "any structure" do
106
+ subject{ build_plane_context }
107
+ after(:each){ subject.assemble(records) }
108
+
109
+ it "builds records by name" do
110
+ records.each{ |r| r.should_receive(:title) }
111
+ end
112
+
113
+ it "builds records by alias" do
114
+ records.each{ |r| r.should_receive(:short_details) }
115
+ end
116
+
117
+ it "builds records by given block" do
118
+ records.each{ |r| r.should_receive(:live?) }
119
+ end
120
+ end
121
+
122
+ context "tree-like structure" do
123
+ let(:conditional_option) { :if }
124
+ let(:fields) {{ :id => 5, :live? => false, :permanent => [], :conditional => [], :conditional_block => [] }}
125
+ after(:each) { build_tree_like_context(conditional_option).assemble(records) }
126
+
127
+ it "creates nested scope for each record" do
128
+ records.each{ |r| r.should_receive(:permanent) }
129
+ end
130
+
131
+ context "when specified :if option" do
132
+ it "creates nested scope if record column is true" do
133
+ records.first.should_not_receive(:conditional)
134
+ records.last.should_receive(:conditional)
135
+ end
136
+
137
+ it "creates nested scope if block returns true" do
138
+ records.first.should_not_receive(:conditional_block)
139
+ records.last.should_receive(:conditional_block)
140
+ end
141
+ end
142
+
143
+ context "when specified :unless option" do
144
+ let(:conditional_option) { :unless }
145
+
146
+ it "creates nested :unless block returns true" do
147
+ records.first.should_receive(:conditional)
148
+ records.last.should_not_receive(:conditional)
149
+ end
150
+
151
+ it "creates nested :unless block returns true" do
152
+ records.first.should_receive(:conditional_block)
153
+ records.last.should_not_receive(:conditional_block)
154
+ end
155
+ end
156
+ end
157
+
158
+ def build_plane_context
159
+ build_context do
160
+ column :title
161
+ column :details, :as => :short_details
162
+ column(:is_active){ |r| r.live? }
163
+ end
164
+ end
165
+
166
+ def build_tree_like_context(conditional_option)
167
+ build_context do
168
+ column :is_active, :as => :live?
169
+ scope_for(:permanent, &dsl)
170
+ scope_for(:conditional, conditional_option => :is_active, &dsl)
171
+ scope_for(:conditional_block, conditional_option => proc{ |r| r.live? }, &dsl)
172
+ end
173
+ end
174
+
175
+ end
176
+
177
+ def build_context(&dsl)
178
+ dsl = Proc.new{} unless block_given?
179
+ TheGrid::Builder::Context.new(options, &dsl)
180
+ end
181
+
182
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe TheGrid::Builder::Json do
4
+ subject { TheGrid::Builder::Json.new(relation, context) }
5
+
6
+ before(:each) { subject.api.stub(:compose!) { subject.api.options[:max_page] = 25 } }
7
+
8
+ let(:relation) { double('Relation').as_null_object }
9
+ let(:context) { create_context.tap { |c| c.stub(:assemble => [1,2,3,4]) } }
10
+ let(:params) {{ :cmd => [:sort], :field => :name, :order => :desc }}
11
+
12
+ let(:meta) {{ "meta" => {"api_key" => context.options[:api_key]}, "columns" => context.visible_columns.stringify_keys }}
13
+ let(:json_schema) {{ "max_page" => 25, "items" => context.assemble }}
14
+ let(:assembled_result) { JSON.parse(subject.assemble_with(params)) }
15
+
16
+ it "merges params with context options" do
17
+ subject.api.should_receive(:compose!).with(params.merge context.options)
18
+ subject.assemble_with params
19
+ end
20
+
21
+ it "generates json with meta information" do
22
+ params[:with_meta] = true
23
+ assembled_result.should eql json_schema.merge(meta)
24
+ end
25
+
26
+ it "generates json without meta" do
27
+ assembled_result.should eql json_schema
28
+ end
29
+
30
+ it "generates json notification when get wrong argument" do
31
+ subject.api.stub(:compose!) { raise ArgumentError, "123" }
32
+ assembled_result.should eql({"status" => "error", "message" => "123"})
33
+ end
34
+
35
+
36
+ def create_context
37
+ TheGrid::Builder::Context.new do
38
+ api_key "hello_world"
39
+ delegate :sort => :articles, :filter => :articles
40
+
41
+ column :name
42
+ column :is_active
43
+ end
44
+ end
45
+
46
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe TheGrid::Config do
4
+ context "when initializes" do
5
+ its(:commands_lookup_scopes) { should eql [] }
6
+ its(:prettify_json) { should be_false }
7
+ end
8
+
9
+ context "when applying specified values" do
10
+ let(:command) { TheGrid::Api::Command }
11
+ let(:builder) { TheGrid::Builder::Json }
12
+ before(:each) { configure(subject) }
13
+
14
+ it "registers specified lookup scopes from configuration" do
15
+ command.scopes.should include(*subject.commands_lookup_scopes)
16
+ end
17
+
18
+ it "sets up default_per_page for Paginate command" do
19
+ command.find(:paginate).default_per_page.should eql subject.default_max_per_page
20
+ end
21
+
22
+ it "sets up prettify_json option for json builder" do
23
+ builder.prettify_json.should eql subject.prettify_json
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def configure(config)
30
+ config.commands_lookup_scopes += %w{ command_scope_1 command_scope_2 }
31
+ config.default_max_per_page = 10
32
+ config.prettify_json = true
33
+ config.apply
34
+ end
35
+ end
@@ -0,0 +1,2 @@
1
+ require 'active_support/all'
2
+ require 'the_grid'
data/the_grid.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "the_grid/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "the_grid"
7
+ s.version = TheGrid::VERSION
8
+ s.authors = ["Sergiy Stotskiy", "Yuriy Buchchenko"]
9
+ s.email = "sergiy.stotskiy@gmail.com"
10
+ s.homepage = "http://github.com/stalniy/grid"
11
+ s.license = "MIT"
12
+ s.summary = %q{Yet another grid api.}
13
+ s.platform = Gem::Platform::RUBY
14
+
15
+ s.description = <<-EOF
16
+ Provides json API for building ActiveRecord::Relation's. It makes much easier to fetch information from database for displaying it using JavaScript MV* based frameworks such as Knockout, Backbone, Angular, etc.
17
+
18
+ Tags: json, grid, api, grid builder, activerecord relation builder, relation
19
+ EOF
20
+
21
+ s.rubyforge_project = "the_grid"
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ s.require_paths = ["lib"]
27
+
28
+ s.add_dependency 'activerecord', '>= 3.0'
29
+ s.add_dependency 'json'
30
+
31
+ # specify any dependencies here; for example:
32
+ s.add_development_dependency "bundler", ">= 1.0.0"
33
+ s.add_development_dependency "rspec", "~> 2.13"
34
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: the_grid
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.7
5
+ platform: ruby
6
+ authors:
7
+ - Sergiy Stotskiy
8
+ - Yuriy Buchchenko
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ! '>='
19
+ - !ruby/object:Gem::Version
20
+ version: '3.0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ! '>='
26
+ - !ruby/object:Gem::Version
27
+ version: '3.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: json
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: bundler
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: 1.0.0
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: 1.0.0
56
+ - !ruby/object:Gem::Dependency
57
+ name: rspec
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: '2.13'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '2.13'
70
+ description: ! 'Provides json API for building ActiveRecord::Relation''s. It makes
71
+ much easier to fetch information from database for displaying it using JavaScript
72
+ MV* based frameworks such as Knockout, Backbone, Angular, etc.
73
+
74
+
75
+ Tags: json, grid, api, grid builder, activerecord relation builder, relation
76
+
77
+ '
78
+ email: sergiy.stotskiy@gmail.com
79
+ executables: []
80
+ extensions: []
81
+ extra_rdoc_files: []
82
+ files:
83
+ - .rvmrc
84
+ - Gemfile
85
+ - README.md
86
+ - Rakefile
87
+ - lib/generators/the_grid/install/install_generator.rb
88
+ - lib/generators/the_grid/install/templates/the_grid.rb
89
+ - lib/the_grid.rb
90
+ - lib/the_grid/api.rb
91
+ - lib/the_grid/api/command.rb
92
+ - lib/the_grid/api/command/batch_remove.rb
93
+ - lib/the_grid/api/command/batch_update.rb
94
+ - lib/the_grid/api/command/filter.rb
95
+ - lib/the_grid/api/command/paginate.rb
96
+ - lib/the_grid/api/command/search.rb
97
+ - lib/the_grid/api/command/sort.rb
98
+ - lib/the_grid/builder.rb
99
+ - lib/the_grid/builder/context.rb
100
+ - lib/the_grid/builder/json.rb
101
+ - lib/the_grid/config.rb
102
+ - lib/the_grid/version.rb
103
+ - spec/api/command/batch_remove_spec.rb
104
+ - spec/api/command/batch_update_spec.rb
105
+ - spec/api/command/filter_spec.rb
106
+ - spec/api/command/paginate_spec.rb
107
+ - spec/api/command/search_spec.rb
108
+ - spec/api/command/sort_spec.rb
109
+ - spec/api/command_spec.rb
110
+ - spec/api_spec.rb
111
+ - spec/builder/context_spec.rb
112
+ - spec/builder/json_spec.rb
113
+ - spec/config_spec.rb
114
+ - spec/spec_helper.rb
115
+ - the_grid.gemspec
116
+ homepage: http://github.com/stalniy/grid
117
+ licenses:
118
+ - MIT
119
+ metadata: {}
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ! '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project: the_grid
136
+ rubygems_version: 2.0.3
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: Yet another grid api.
140
+ test_files: []