simple-json 1.0.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.
@@ -0,0 +1,40 @@
1
+ # ///////////////////////////////////////////////////////////////////////////////////////
2
+ #
3
+ # Author:: lp (mailto:lp@spiralix.org)
4
+ # Copyright:: 2009 Louis-Philippe Perron - Released under the terms of the MIT license
5
+ #
6
+ # :title:SimpleJSON
7
+ class SimpleJSON
8
+ require File.join( File.dirname( File.expand_path(__FILE__)), 'simple_json_helpers')
9
+ require File.join( File.dirname( File.expand_path(__FILE__)), 'simple_json_db')
10
+ require File.join( File.dirname( File.expand_path(__FILE__)), 'simple_json_bootstrap')
11
+
12
+ def self.echo(opts=nil)
13
+ lambda { |env| CrashProof.wrap { Bootstrap.config(opts); Response.generate( Request.parse( Body.get(env))) }}
14
+ end
15
+
16
+ def self.set(opts=nil)
17
+ lambda { |env| CrashProof.wrap { Bootstrap.config(opts); Response.generate( @@store.set( Request.parse( Body.get(env)))) }}
18
+ end
19
+
20
+ def self.add(opts=nil)
21
+ lambda { |env| CrashProof.wrap { Bootstrap.config(opts); Response.generate( @@store.add( Request.parse( Body.get(env)))) }}
22
+ end
23
+
24
+ def self.delete(opts=nil)
25
+ lambda { |env| CrashProof.wrap { Bootstrap.config(opts); Response.generate( @@store.delete( Request.parse( Body.get(env)))) }}
26
+ end
27
+
28
+ def self.get(opts=nil)
29
+ lambda { |env| CrashProof.wrap { Bootstrap.config(opts); Response.generate( @@store.get( Request.parse( Body.get(env)))) }}
30
+ end
31
+
32
+ def self.query(opts=nil)
33
+ lambda { |env| CrashProof.wrap { Bootstrap.config(opts); Response.generate( @@store.query( Request.parse( Body.get(env)))) }}
34
+ end
35
+
36
+ def self.rack_mock(m,data,opts=nil)
37
+ CrashProof.wrap { Bootstrap.config(opts); Response.generate( @@store.send( m, Request.parse( data))) }
38
+ end
39
+
40
+ end
@@ -0,0 +1,46 @@
1
+ class SimpleJSON
2
+ def self.bootstrap(opts)
3
+ Bootstrap.config(opts)
4
+ end
5
+ # ///////////////////////////////////////////////////////////////////////////////////////
6
+ #
7
+ # Author:: lp (mailto:lp@spiralix.org)
8
+ # Copyright:: 2009 Louis-Philippe Perron - Released under the terms of the MIT license
9
+ #
10
+ # :title:SimpleJSON::Bootstrap
11
+ module Bootstrap
12
+ def self.config(opts)
13
+ unless opts.nil?
14
+ opts = eval(File.open(opts, 'r').read) if opts.is_a?(String)
15
+ if opts.is_a?(Hash)
16
+ change = Hash.new
17
+ if opts['AMAZON_ACCESS_KEY_ID'] and ENV['AMAZON_ACCESS_KEY_ID'] != opts['AMAZON_ACCESS_KEY_ID']
18
+ ENV['AMAZON_ACCESS_KEY_ID'] = opts['AMAZON_ACCESS_KEY_ID']
19
+ change[:@access_key_id] = opts['AMAZON_ACCESS_KEY_ID']
20
+ end
21
+ if opts['AMAZON_SECRET_ACCESS_KEY'] and ENV['AMAZON_SECRET_ACCESS_KEY'] != opts['AMAZON_SECRET_ACCESS_KEY']
22
+ ENV['AMAZON_SECRET_ACCESS_KEY'] = opts['AMAZON_SECRET_ACCESS_KEY']
23
+ change[:@secret_access_key] = opts['AMAZON_SECRET_ACCESS_KEY']
24
+ end
25
+
26
+ if SimpleJSON.class_variables.include?('@@store') and ( ! change.empty? or opts['AMAZON_DOMAIN'])
27
+ store = SimpleJSON.class_eval { class_variable_get(:@@store) }
28
+ if ! change.empty?
29
+ sdb = store.instance_variable_get(:@sdb)
30
+ change.each do |k,v|
31
+ sdb.instance_variable_set(k,v)
32
+ end
33
+ end
34
+ if opts['AMAZON_DOMAIN']
35
+ store.instance_variable_set(:@domain,opts['AMAZON_DOMAIN'])
36
+ store.instance_eval('create_domain unless domain_exist?')
37
+ end
38
+ else
39
+ store = SimpleJSON::DB.new(opts['AMAZON_DOMAIN']) if opts['AMAZON_DOMAIN']
40
+ SimpleJSON.class_eval { class_variable_set(:@@store, store) }
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,108 @@
1
+ class SimpleJSON
2
+ # ///////////////////////////////////////////////////////////////////////////////////////
3
+ #
4
+ # Author:: lp (mailto:lp@spiralix.org)
5
+ # Copyright:: 2009 Louis-Philippe Perron - Released under the terms of the MIT license
6
+ #
7
+ # :title:SimpleJSON::DB
8
+ class DB
9
+ require 'aws_sdb'
10
+
11
+ # id generated in client?
12
+ # in js = < '' + date.getTime() + Math.floor(Math.random()*1000) >
13
+ def initialize(domain)
14
+ @domain = domain
15
+ @sdb = AwsSdb::Service.new(:logger=>LogDuck.new)
16
+ create_domain unless domain_exist?
17
+ end
18
+
19
+ def set(data)
20
+ # in: data = {'id' => {:key1 => value1, :key2 => value2}}
21
+ # out: data = {'id' => true} || {'id' => {"error"=>"message"}}
22
+ parse(data) {|k,v| @sdb.put_attributes(@domain,k,v) }
23
+ end
24
+
25
+ def add(data)
26
+ # in: data = {'id' => {:key1 => value1, :key2 => value2}}
27
+ # out: data = {'id' => true} || {'id' => {"error"=>"message"}}
28
+ parse(data) {|k,v| @sdb.put_attributes(@domain,k,v,false) }
29
+ end
30
+
31
+ def get(data)
32
+ # in: data = {'id' => {:key1 => nil, :key2 => nil}}
33
+ # out: data = {'id' => {:key1 => value1, :key2 => value2}}
34
+ parse(data) { |k,v| query_get(k,v) }
35
+ end
36
+
37
+ def delete(data)
38
+ # in: data = {'id' => nil}
39
+ # out: data = {'id' => true}
40
+ parse(data) {|k,v| @sdb.delete_attributes(@domain,k) }
41
+ end
42
+
43
+ def query(data)
44
+ # in: data = {'query' => {:key1 => nil, :key2 => nil}}
45
+ # out: data = {'id' => {:key1 => value1, :key2 => value2}}
46
+ parse(data) {|k,v| query_domain(k,v) }
47
+ end
48
+
49
+ private
50
+
51
+ def parse(data,&block)
52
+ data.to_a.inject(Hash.new) do |mem,obj|
53
+ begin
54
+ r_data = block.call(obj[0],obj[1])
55
+ if r_data.nil?
56
+ mem[obj[0]] = true
57
+ elsif r_data.is_a?(Hash)
58
+ mem[obj[0]] = r_data
59
+ else
60
+ mem[obj[0]] = [false, "SDB Error. Unable to 'put attributes'"]
61
+ end
62
+ rescue => ex
63
+ mem[obj[0]] = [false, "#{ex.class}: #{ex.message}"]
64
+ end
65
+ mem
66
+ end
67
+ end
68
+
69
+ def query_domain(k,v)
70
+ ids = get_id(k)
71
+ if v.nil?
72
+ return ids.inject(Hash.new) { |mem,obj| mem[obj] = nil; mem }
73
+ else
74
+ if ids.is_a?(Array)
75
+ ids.inject(Hash.new) { |mem,id| mem[id] = query_get(id,v); mem }
76
+ else
77
+ return [false,"Query Failed: v:#{v.inspect} | r:#{r_ids.inspect}"]
78
+ end
79
+ end
80
+ end
81
+
82
+ def query_get(k,v)
83
+ r_data = @sdb.get_attributes(@domain,k)
84
+ if v.nil? || v == true || v == false
85
+ r_data
86
+ else
87
+ v.to_a.inject(Hash.new) { |mem,obj| mem[obj[0]] = r_data[obj[0]]; mem }
88
+ end
89
+ end
90
+
91
+ def get_id(q,token=nil)
92
+ ids,q_id = @sdb.query(@domain,q,token)
93
+ ids += get_id(q,q_id) if q_id != ''
94
+ return ids
95
+ end
96
+
97
+ def create_domain
98
+ @sdb.create_domain(@domain)
99
+ end
100
+
101
+ def domain_exist?
102
+ domains, dummy = @sdb.list_domains
103
+ domains.include?(@domain)
104
+ end
105
+
106
+ class LogDuck; def debug(*args); end; end
107
+ end
108
+ end
@@ -0,0 +1,56 @@
1
+ class SimpleJSON
2
+ require 'json'
3
+ # ///////////////////////////////////////////////////////////////////////////////////////
4
+ #
5
+ # Author:: lp (mailto:lp@spiralix.org)
6
+ # Copyright:: 2009 Louis-Philippe Perron - Released under the terms of the MIT license
7
+ #
8
+ # :title:SimpleJSON::Request
9
+ module Request
10
+ def self.parse(data)
11
+ JSON.parse(data)
12
+ end
13
+ end
14
+
15
+ # ///////////////////////////////////////////////////////////////////////////////////////
16
+ #
17
+ # Author:: lp (mailto:lp@spiralix.org)
18
+ # Copyright:: 2009 Louis-Philippe Perron - Released under the terms of the MIT license
19
+ #
20
+ # :title:SimpleJSON::Response
21
+ module Response
22
+ def self.generate(data)
23
+ return [200, { 'Content-Type' => 'application/json' }, JSON.generate(data)]
24
+ end
25
+ end
26
+
27
+ # ///////////////////////////////////////////////////////////////////////////////////////
28
+ #
29
+ # Author:: lp (mailto:lp@spiralix.org)
30
+ # Copyright:: 2009 Louis-Philippe Perron - Released under the terms of the MIT license
31
+ #
32
+ # :title:SimpleJSON::Body
33
+ module Body
34
+ def self.get(env)
35
+ data = env['rack.input'].read
36
+ return data
37
+ end
38
+ end
39
+
40
+ # ///////////////////////////////////////////////////////////////////////////////////////
41
+ #
42
+ # Author:: lp (mailto:lp@spiralix.org)
43
+ # Copyright:: 2009 Louis-Philippe Perron - Released under the terms of the MIT license
44
+ #
45
+ # :title:SimpleJSON::CrashProof
46
+ module CrashProof
47
+ def self.wrap(&block)
48
+ begin
49
+ block.call
50
+ rescue
51
+ [200, { 'Content-Type' => 'application/json' }, "{\"ERROR\":{\"class\":\"#{$!.class}\",\"message\":\"#{$!.message}\"}}"]
52
+ end
53
+ end
54
+ end
55
+
56
+ end
@@ -0,0 +1,145 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'json'
4
+
5
+ # require File.join( File.dirname( File.expand_path(__FILE__)), '..','aws-sdb','lib','aws_sdb')
6
+ require 'aws_sdb'
7
+ require File.join( File.dirname( File.expand_path(__FILE__)), '..','simple_json')
8
+
9
+ class TestSimpleJSONDB < Test::Unit::TestCase
10
+ BEGIN {
11
+ @@id = Time.now.to_i.to_s + rand(1000).to_s
12
+ }
13
+
14
+ def setup
15
+ SimpleJSON.bootstrap(File.join( File.dirname( File.expand_path(__FILE__)), '..','simple_json_config.rb'))
16
+ end
17
+
18
+ def test_01_bootload
19
+ @@sdb = AwsSdb::Service.new
20
+ config = eval(File.open(File.join( File.dirname( File.expand_path(__FILE__)), '..','simple_json_config.rb'), 'r').read)
21
+ assert(@@sdb.list_domains[0].include?(config['AMAZON_DOMAIN']), 'boot?')
22
+ end
23
+
24
+ def test_02_firstset
25
+ @@i_data = {@@id => {'name' => @@id, 'test' => 'done'}}
26
+
27
+ o_data = SimpleJSON.rack_mock(:set, JSON.generate(@@i_data))
28
+ assert(o_data.is_a?(Array),'return HTTP?')
29
+ assert(o_data[0] == 200,'HTTP 200?')
30
+ assert(o_data[1].is_a?(Hash),'HTTP Headers?')
31
+ assert(o_data[1]['Content-Type'] == 'application/json', 'JSON?')
32
+ assert(o_data[2].is_a?(String),'JSON String?')
33
+
34
+ p_data = JSON.parse(o_data[2])
35
+ assert(p_data.is_a?(Hash),'JSON Parse?')
36
+ assert(p_data.include?(@@id),'returned ID?')
37
+ assert(p_data[@@id] == true,'set is true?')
38
+ end
39
+
40
+ def test_03_get_one
41
+ t_data = {@@id => nil}
42
+ o_data = JSON.parse( SimpleJSON.rack_mock(:get, JSON.generate(t_data))[2])
43
+ @@i_data[@@id].each do |k,v|
44
+ assert(o_data[@@id][k][0] == v, "get <#{k}> in first set")
45
+ end
46
+ end
47
+
48
+ def test_04_get_one_attribute
49
+ t_data = {@@id => {'name' => nil}}
50
+ o_data = JSON.parse( SimpleJSON.rack_mock(:get, JSON.generate(t_data))[2])
51
+ assert(t_data[@@id].size == o_data[@@id].size, 'get one attribute')
52
+ end
53
+
54
+ def test_05_set_one_more
55
+ t_data = {@@id => {'more' => 'data'}}
56
+ o_data = JSON.parse( SimpleJSON.rack_mock(:set, JSON.generate(t_data))[2])
57
+ assert(o_data[@@id] == true,'set is true?')
58
+
59
+ o_data = JSON.parse( SimpleJSON.rack_mock(:get, JSON.generate({@@id => nil}))[2])
60
+ @@i_data[@@id].merge!(t_data[@@id])
61
+ @@i_data[@@id].each do |k,v|
62
+ assert(o_data[@@id][k][0] == v, "get <#{k}> in first get")
63
+ end
64
+ end
65
+
66
+ def test_06_set_overwrite
67
+ o_data = JSON.parse( SimpleJSON.rack_mock(:set, JSON.generate({@@id => {'more' => 'data2'}}))[2])
68
+ assert(o_data[@@id] == true,'set is true?')
69
+
70
+ o_data = JSON.parse( SimpleJSON.rack_mock(:get, JSON.generate({@@id => nil}))[2])
71
+ assert(o_data[@@id]['more'].size == 1, 'overwrite data?')
72
+ end
73
+
74
+ def test_07_set_append
75
+ o_data = JSON.parse( SimpleJSON.rack_mock(:add, JSON.generate({@@id => {'more' => 'data3'}}))[2])
76
+ assert(o_data[@@id] == true,'set is true?')
77
+
78
+ o_data = JSON.parse( SimpleJSON.rack_mock(:get, JSON.generate({@@id => nil}))[2])
79
+ assert(o_data[@@id]['more'].size == 2, 'append data?')
80
+ end
81
+
82
+ def test_08_query_all
83
+ o_data = JSON.parse( SimpleJSON.rack_mock(:query, JSON.generate({'' => nil}))[2])
84
+ assert(o_data.is_a?(Hash),'query all is not a Hash?')
85
+ assert(o_data.size == 1,'query all Hash contains more than one key value pair')
86
+ assert(o_data.has_key?(''),'query all Hash does not contain the query string as key')
87
+ assert(o_data[''].to_a.map { |obj| obj[1] }.uniq.size == 1,'query all Hash does not bring id => nil? ')
88
+ end
89
+
90
+ def test_09_query_specific_all
91
+ query = "['name' = '#{@@id}']"
92
+ t_data = {query => true}
93
+ o_data = JSON.parse( SimpleJSON.rack_mock(:query, JSON.generate(t_data))[2])
94
+ assert(o_data.is_a?(Hash),'query specific all is not a Hash?')
95
+ assert(o_data.size == 1,'query specific all Hash contains more than one key value pair')
96
+ assert(o_data.has_key?(query),'query specific all Hash does not contain the query string as key')
97
+ assert(o_data[query].has_key?(@@id))
98
+ assert(o_data[query][@@id].size == @@i_data[@@id].size)
99
+ end
100
+
101
+ def test_10_query_specific_none
102
+ query = "['name' = '#{@@id}']"
103
+ t_data = {query => nil}
104
+ o_data = JSON.parse( SimpleJSON.rack_mock(:query, JSON.generate(t_data))[2])
105
+ assert(o_data.is_a?(Hash))
106
+ assert(o_data.size == 1)
107
+ assert(o_data.has_key?(query))
108
+ assert(o_data[query].has_key?(@@id))
109
+ assert(o_data[query][@@id].nil?)
110
+ end
111
+
112
+ def test_11_query_specific_some
113
+ query = "['name' = '#{@@id}']"
114
+ t_data = {query => {'name' => nil, 'more' => nil}}
115
+ o_data = JSON.parse( SimpleJSON.rack_mock(:query, JSON.generate(t_data))[2])
116
+ assert(o_data.is_a?(Hash))
117
+ assert(o_data.size == 1)
118
+ assert(o_data.has_key?(query))
119
+ assert(o_data[query].has_key?(@@id))
120
+ assert(o_data[query][@@id].size == 2)
121
+ end
122
+
123
+ def test_12_delete
124
+ o_data = JSON.parse( SimpleJSON.rack_mock(:delete, JSON.generate({@@id => nil}))[2])
125
+ assert(o_data.is_a?(Hash))
126
+ assert(o_data.size == 1)
127
+ assert(o_data.has_key?(@@id))
128
+ assert(o_data[@@id] == true)
129
+
130
+ o_data = JSON.parse( SimpleJSON.rack_mock(:get, JSON.generate({@@id => nil}))[2])
131
+ assert(o_data.is_a?(Hash))
132
+ assert(o_data.size == 1)
133
+ assert(o_data.has_key?(@@id))
134
+ assert(o_data[@@id].is_a?(Hash))
135
+ assert(o_data[@@id].empty?)
136
+ end
137
+
138
+ def test_13_other_config
139
+ domain = 'other_test_domain'
140
+ o_data = JSON.parse( SimpleJSON.rack_mock(:delete, JSON.generate({@@id => nil}), {'AMAZON_DOMAIN' => domain})[2])
141
+ assert(@@sdb.list_domains[0].include?(domain), 'other domain')
142
+ @@sdb.delete_domain(domain)
143
+ end
144
+
145
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple-json
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Louis-Philippe Perron
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-01 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rack
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: json
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.0.0
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: aws-sdb
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.0.0
44
+ version:
45
+ description: SimpleJSON is a Rack based JSON frontend server to Amazon's SimpleDB, designed to be used as a simple backend data servers for client side web apps.
46
+ email: lp@spiralix.org
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ extra_rdoc_files: []
52
+
53
+ files:
54
+ - lib/simple_json.rb
55
+ - lib/simple_json_bootstrap.rb
56
+ - lib/simple_json_db.rb
57
+ - lib/simple_json_helpers.rb
58
+ - test/tc_simple_json.rb
59
+ has_rdoc: true
60
+ homepage: http://simple-json.rubyforge.org/
61
+ licenses: []
62
+
63
+ post_install_message:
64
+ rdoc_options: []
65
+
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ requirements:
81
+ - an Amazon Web Service account to access SimpleDB
82
+ rubyforge_project: SimpleJSON
83
+ rubygems_version: 1.3.5
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: Rack app, JSON frontend to Amazon's SimpleDB
87
+ test_files:
88
+ - test/tc_simple_json.rb