protoj 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ ## 0.1.0 ##
2
+
3
+ * init
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2004-2012 Hao Hong
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,4 @@
1
+ ProtoJ
2
+ ==========
3
+
4
+ * Please take a look at the test cases. That will show you how to use this gem
@@ -0,0 +1,13 @@
1
+ proto_j_lib_path = File.expand_path('../../lib', __FILE__)
2
+ $:.unshift(proto_j_lib_path) if File.directory?(proto_j_lib_path) && !$:.include?(proto_j_lib_path)
3
+
4
+ require 'json'
5
+
6
+ require 'active_support/inflector'
7
+ require 'active_support/core_ext'
8
+
9
+ require 'proto_j/exception/type_mismatch'
10
+ require 'proto_j/associations/collection_proxy'
11
+ require 'proto_j/associations/has_many_association'
12
+ require 'proto_j/base'
13
+ require 'proto_j/utils'
@@ -0,0 +1,32 @@
1
+ module ActiveJson
2
+ module ActiveRecord::Owner
3
+ def self.included(klass)
4
+ klass.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def proto_j(key, options={})
9
+ db_column = options[:db_column] || "#{key}_json"
10
+ settings_class = options[:class] || "#{key.to_s.classify}".constantize
11
+
12
+ before_save do |m|
13
+ attributes = {}
14
+ attributes[db_column] = m.send(key).to_json
15
+ m.assign_attributes(attributes, :without_protection => true)
16
+ end
17
+
18
+ define_method key do
19
+ var_name = "@#{key}"
20
+ settings = instance_variable_get(var_name)
21
+
22
+ unless settings
23
+ settings = settings_class.new(attributes[db_column.to_s])
24
+ instance_variable_set(var_name, settings)
25
+ end
26
+
27
+ settings
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,31 @@
1
+ module ProtoJ
2
+ module Associations
3
+ class CollectionProxy
4
+ instance_methods.each { |m| undef_method m unless m.to_s =~ /^(?:nil\?|send|object_id|to_a)$|^__|^respond_to/ }
5
+
6
+ delegate :target, :concat, :new, :to_hash, :clear, :update, :to => :@association
7
+
8
+ def initialize(association)
9
+ @association = association
10
+ end
11
+
12
+ def ===(other)
13
+ other === target
14
+ end
15
+
16
+ def to_ary
17
+ target.dup
18
+ end
19
+ alias_method :to_a, :to_ary
20
+
21
+ def <<(*records)
22
+ @association.concat(records) && self
23
+ end
24
+ alias_method :push, :<<
25
+
26
+ def method_missing(method, *args, &block)
27
+ target.send(method, *args, &block)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,64 @@
1
+ module ProtoJ
2
+ module Associations
3
+ class HasManyAssociation
4
+ attr_reader :target
5
+
6
+ def initialize(klass)
7
+ @klass = klass
8
+ @target = []
9
+ @proxy = CollectionProxy.new(self)
10
+ end
11
+
12
+ def reader
13
+ @proxy
14
+ end
15
+
16
+ def concat(*records)
17
+ records = records.flatten
18
+
19
+ records.each do |record|
20
+ unless record.is_a?(@klass)
21
+ raise ::ProtoJ::Exception::TypeMismatch.new("require #{@klass}, but got #{record.class}")
22
+ end
23
+ end
24
+
25
+ @target.concat(records)
26
+ end
27
+
28
+ def new
29
+ child = @klass.new
30
+ @target << child
31
+ child
32
+ end
33
+
34
+ def to_hash
35
+ @target.collect { |t| t.to_hash }
36
+ end
37
+
38
+ def clear
39
+ @target = []
40
+ @proxy
41
+ end
42
+
43
+ def update(json=[])
44
+ new_target = []
45
+
46
+ if json.is_a?(Array)
47
+ array = json
48
+ else
49
+ array = JSON.parse(json)
50
+ end
51
+
52
+ if array.is_a? Array
53
+ array.each do |item|
54
+ new_target << @klass.new(item)
55
+ end
56
+
57
+ @target = new_target
58
+ end
59
+
60
+ @target
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,171 @@
1
+ module ProtoJ
2
+ class Base
3
+ class << self
4
+ def fields
5
+ begin
6
+ return class_variable_get("@@fields")
7
+ rescue
8
+ var = []
9
+ class_variable_set("@@fields", var)
10
+ return var
11
+ end
12
+ end
13
+
14
+ def associations
15
+ begin
16
+ return class_variable_get("@@associations")
17
+ rescue
18
+ var = []
19
+ class_variable_set("@@associations", var)
20
+ return var
21
+ end
22
+ end
23
+
24
+ def field(key, options={})
25
+ fields << { key: key, options: options }
26
+
27
+ define_method key do
28
+ normalize_value(instance_variable_get("@#{key}"), options)
29
+ end
30
+ define_method "#{key}=" do |val|
31
+ val = normalize_value(val, options)
32
+ instance_variable_set("@#{key}", val)
33
+ end
34
+ end
35
+
36
+ def has_one(key, options={})
37
+ options[:class] ||= "#{self.name}::#{key.to_s.capitalize}".constantize
38
+ associations << { key: key, options: options, type: :has_one, class: options[:class] }
39
+
40
+ define_method key do
41
+ instance_variable_get("@#{key}")
42
+ end
43
+ define_method "#{key}=" do |val|
44
+ # TODO change to association exception class way
45
+ raise 'Class Mismatch' unless val.is_a?(options[:class])
46
+ instance_variable_set("@#{key}", val)
47
+ end
48
+ end
49
+
50
+ def has_many(key, options={})
51
+ options[:class] ||= "#{self.name}::#{key.to_s.singularize.capitalize}".constantize
52
+ associations << { key: key, options: options, type: :has_many, class: options[:class] }
53
+
54
+ define_method key do
55
+ instance_variable_get("@#{key}").reader
56
+ end
57
+ end
58
+ end
59
+
60
+ def initialize(json={})
61
+ if json.is_a?(Hash)
62
+ hash = json
63
+ else
64
+ hash = JSON.parse(json) rescue {}
65
+ end
66
+
67
+ self.class.fields.each do |f|
68
+ key = f[:key]
69
+ instance_variable_set("@#{key}", hash[key.to_s])
70
+ end
71
+
72
+ self.class.associations.each do |a|
73
+ key = a[:key]
74
+
75
+ case a[:type].to_sym
76
+ when :has_one
77
+ instance_variable_set("@#{key}", a[:class].new(hash[key.to_s]))
78
+ when :has_many
79
+ instance_variable_set("@#{key}", Associations::HasManyAssociation.new(a[:class]))
80
+
81
+ (hash[key.to_s] || []).each do |item|
82
+ instance_variable_get("@#{key}").reader << a[:class].new(item)
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ def update(json={})
89
+ if json.is_a?(Hash)
90
+ hash = json
91
+ else
92
+ hash = JSON.parse(json) rescue {}
93
+ end
94
+
95
+ self.class.fields.each do |f|
96
+ key = f[:key].to_s
97
+ if hash.has_key?(key)
98
+ self.send("#{key}=", hash[key])
99
+ end
100
+ end
101
+
102
+ self.class.associations.each do |a|
103
+ key = a[:key].to_s
104
+
105
+ if hash.has_key?(key)
106
+ self.send(key).update(hash[key])
107
+ end
108
+ end
109
+ end
110
+
111
+ def to_json
112
+ to_hash.to_json
113
+ end
114
+
115
+ def to_hash
116
+ hash = {}
117
+
118
+ self.class.fields.each do |f|
119
+ hash[f[:key].to_s] = ::ProtoJ::Utils.to_sorted_hash(self.send(f[:key]))
120
+ end
121
+
122
+ self.class.associations.each do |a|
123
+ hash[a[:key].to_s] = self.send(a[:key]).to_hash
124
+ end
125
+
126
+ Hash[hash.sort]
127
+ end
128
+
129
+ private
130
+
131
+ def get(key)
132
+ instance_variable_get("@#{key}")
133
+ end
134
+
135
+ def set(key, val)
136
+ var = instance_variable_get("@#{key}")
137
+ unless var
138
+ var = klass.new(@hash[key.to_s])
139
+ instance_variable_set("@#{key}", var)
140
+ end
141
+ var
142
+ end
143
+
144
+ def normalize_value(value, field_options)
145
+ field_type = field_options[:type]
146
+
147
+ if field_type
148
+ case field_type.name
149
+ when 'Array'
150
+ case value
151
+ when Array
152
+ when String
153
+ value = JSON.parse(value) rescue []
154
+ else
155
+ value = []
156
+ end
157
+ when 'Hash'
158
+ case value
159
+ when Hash
160
+ when String
161
+ value = JSON.parse(value) rescue {}
162
+ else
163
+ value = {}
164
+ end
165
+ end
166
+ end
167
+
168
+ return value
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,5 @@
1
+ module ProtoJ
2
+ module Exception
3
+ class TypeMismatch < ::Exception; end
4
+ end
5
+ end
@@ -0,0 +1,21 @@
1
+ class ProtoJ::Utils
2
+ def self.to_sorted_hash(hash)
3
+ if hash.is_a? Hash
4
+ hash = Hash[hash.sort]
5
+ hash.each_pair do |k,v|
6
+ hash[k] = to_sorted_hash(v)
7
+ end
8
+ return hash
9
+ elsif hash.is_a? Array
10
+ return hash.collect do |item|
11
+ to_sorted_hash(item)
12
+ end
13
+ else
14
+ return hash
15
+ end
16
+ end
17
+
18
+ def self.to_sorted_json(json)
19
+ to_sorted_hash(JSON.parse(json)).to_json
20
+ end
21
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: protoj
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Hao Hong
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-29 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: json
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.7'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.7'
30
+ - !ruby/object:Gem::Dependency
31
+ name: activesupport
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '3.2'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '3.2'
46
+ description: Allows user to define a JSON's schema with ruby object.
47
+ email: agate.hao@gmail.com
48
+ executables: []
49
+ extensions: []
50
+ extra_rdoc_files: []
51
+ files:
52
+ - CHANGELOG.md
53
+ - MIT-LICENSE
54
+ - README.md
55
+ - lib/proto_j/active_record/owner.rb
56
+ - lib/proto_j/associations/collection_proxy.rb
57
+ - lib/proto_j/associations/has_many_association.rb
58
+ - lib/proto_j/base.rb
59
+ - lib/proto_j/exception/type_mismatch.rb
60
+ - lib/proto_j/utils.rb
61
+ - lib/proto_j.rb
62
+ homepage: http://honghao.me
63
+ licenses:
64
+ - MIT
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: 1.9.2
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 1.8.24
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: Definable JSON Object Builder
87
+ test_files: []