jsoning 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e4d959011ca794ad4e783b547f7cbfe0e503cbb7
4
+ data.tar.gz: 4c6fea6be0eac306f0ffe0c7e5bd30c622e8efda
5
+ SHA512:
6
+ metadata.gz: 699d0e152d55a6724a46dd6c35c5cc3840e69ee9f5c5f28d79c755e208635596b92d80193c4b5c0f12208e5d00a87aa5f5c80edf4a3d4e0ef8fa3628e7c12863
7
+ data.tar.gz: 1cfff70c84f877c08397c6511922b0b5c2415b4eff8059177ed6b86a11e315ae5d6037ab16acae3e12cc0acac6e41f93b4693290b9bd3b113e08ee24f4189999
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ *.swp
12
+ *.swo
13
+ *.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler -v 1.10.6
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in jsoning.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Adam Pahlevi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,171 @@
1
+ # Jsoning
2
+
3
+ Turning object into json can sometimes be frustrating. With Jsoning, you could turn your
4
+ everyday ruby object into JSON, very easily. It should work with
5
+ any Ruby object there is. Kiss good bye to complexity
6
+
7
+ [![Code Climate](https://codeclimate.com/github/saveav/jsoning/badges/gpa.svg)](https://codeclimate.com/github/saveav/jsoning)
8
+ [ ![Codeship Status for saveav/bali](https://codeship.com/projects/b58d3950-493b-0133-a217-168d58eb1296/status?branch=release)](https://codeship.com/projects/105558)
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'Jsoning'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install jsoning
25
+
26
+ ## Assumptions
27
+
28
+ We have classes already defined as follow:
29
+
30
+ ```ruby
31
+ module My; end
32
+ class My::User
33
+ attr_accessor :name, :age, :gender
34
+ attr_accessor :taken_degree
35
+ attr_accessor :books
36
+
37
+ def initialize
38
+ self.books = []
39
+ end
40
+ end
41
+ class My::Book
42
+ attr_accessor :name
43
+ def initialize(name)
44
+ self.name = name
45
+ end
46
+ end
47
+ class My::UserDegree
48
+ attr_accessor :faculty
49
+ attr_accessor :degree_name
50
+
51
+ def to_s
52
+ "#{degree_name} at #{faculty}"
53
+ end
54
+ end
55
+ ```
56
+
57
+ ## Usage
58
+
59
+ Say, we want to serialize User. First, we have to define the serializer for `My::User`:
60
+
61
+ ```ruby
62
+ Jsoning.for(My::User) do
63
+ key :name
64
+ key :years_old, from: :age
65
+ key :gender, default: "male"
66
+ key :books
67
+ key :degree_detail, from: :taken_degree
68
+ end
69
+ ```
70
+
71
+ But, as user have `books` and `taken_degree` which could be an instance of `My::Book` and `My::UserDegree`,
72
+ on which Jsoning has no clue about how to serialize... you should define serializer for them as well:
73
+
74
+ ```ruby
75
+ Jsoning.for(My::Book) do
76
+ key :name
77
+ end
78
+
79
+ Jsoning.for(My::UserDegree) do
80
+ key :faculty
81
+ key :degree, from: :degree_name
82
+ end
83
+ ```
84
+
85
+ So, where you put those codes? Anywhere you want it just make sure it is loaded/required. You can put it inside
86
+ a file for each serializer, or a single file for all serializer. Anyway you want it.
87
+
88
+ After those serializers are defined, we can have a test. Assume we let user to have value as follow:
89
+
90
+ ```ruby
91
+ user = My::User.new
92
+ user.name = "Adam Baihaqi"
93
+ user.age = 21
94
+ user.books << My::Book.new("Quiet: The Power of Introvert")
95
+ user.books << My::Book.new("Harry Potter and the Half-Blood Prince")
96
+ user
97
+ ```
98
+
99
+ To serialize `user`, we only need to call:
100
+
101
+ ```ruby
102
+ Jsoning(user)
103
+ ```
104
+
105
+ Which will return:
106
+
107
+ ```json
108
+ {"name":"Adam Baihaqi","years_old":21,"gender":"male","books":[{"name":"Quiet: The Power of Introvert"},{"name":"Harry Potter and the Half-Blood Prince"}],"degree_detail":null}
109
+ ```
110
+
111
+ We can also pretty-print the value, which usually is bit slower though, by calling:
112
+
113
+ ```ruby
114
+ Jsoning(user, pretty: true)
115
+ ```
116
+
117
+ Which will return:
118
+
119
+ ```json
120
+ {
121
+ "name": "Adam Baihaqi",
122
+ "years_old": 21,
123
+ "gender": "male",
124
+ "books": [
125
+ {
126
+ "name": "Quiet: The Power of Introvert"
127
+ },
128
+ {
129
+ "name": "Harry Potter and the Half-Blood Prince"
130
+ }
131
+ ],
132
+ "degree_detail": null
133
+ }
134
+ ```
135
+
136
+ Now, let us fill in the degree detail:
137
+
138
+ ```ruby
139
+ degree = My::UserDegree.new
140
+ degree.faculty = "School of IT"
141
+ degree.degree_name = "B.Sc. (Hons) Computer Science"
142
+ user.taken_degree = degree
143
+ ```
144
+
145
+ Jsoning the user with pretty set to true, will return:
146
+
147
+ ```json
148
+ {
149
+ "name": "Adam Baihaqi",
150
+ "years_old": 21,
151
+ "gender": "male",
152
+ "books": [
153
+ {
154
+ "name": "Quiet: The Power of Introvert"
155
+ },
156
+ {
157
+ "name": "Harry Potter and the Half-Blood Prince"
158
+ }
159
+ ],
160
+ "degree_detail": {
161
+ "faculty": "School of IT",
162
+ "degree": "B.Sc. (Hons) Computer Science"
163
+ }
164
+ }
165
+ ```
166
+
167
+ Wish it to be helpful for you! Enjoy!
168
+
169
+ ## License
170
+
171
+ The gem is proudly available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "jsoning"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/jsoning.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'jsoning/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "jsoning"
8
+ spec.version = Jsoning::VERSION
9
+ spec.authors = ["Adam Pahlevi"]
10
+ spec.email = ["adam.pahlevi@gmail.com"]
11
+
12
+ spec.summary = %q{Turns any of your everyday ruby objects to json formats, the way you always want it}
13
+ spec.description = %q{Turning object into json can sometimes be frustrating. With Jsoning, you could turn your
14
+ everyday ruby object into JSON, very easily. It should work with
15
+ any Ruby object there is. Kiss good bye to complexity!}
16
+ spec.homepage = "http://github.com/saveav/jsoning"
17
+ spec.license = "MIT"
18
+
19
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.10"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.3"
27
+ end
@@ -0,0 +1,43 @@
1
+ class Jsoning::ForDsl
2
+ attr_reader :protocol
3
+
4
+ def initialize(protocol)
5
+ @protocol = protocol
6
+ end
7
+
8
+ # args is first specifying the name for variable to be displayed in JSON docs,
9
+ # and then the options. options are optional, if set, it can contains:
10
+ # - from
11
+ # - null
12
+ # - default
13
+ def key *args
14
+ mapped_to = nil
15
+ mapped_from = nil
16
+ options = {}
17
+
18
+ args.each do |arg|
19
+ if arg.is_a?(String) || arg.is_a?(Symbol)
20
+ mapped_to = arg
21
+ elsif arg.is_a?(Hash)
22
+ options = arg
23
+ end
24
+ end
25
+
26
+ mapper = Jsoning::Mapper.new
27
+ if block_given?
28
+ raise Jsoning::Error, "Cannot parse block to key"
29
+ else
30
+ mapped_from = options.delete(:from) || options.delete("from") || mapped_to
31
+ mapper.parallel_variable = mapped_from
32
+ end
33
+
34
+ mapper.name = mapped_to
35
+ mapper.default_value = options.delete(:default) || options.delete("default")
36
+ mapper.nullable = options.delete(:null)
37
+ mapper.nullable = options.delete("null") if mapper.nullable.nil?
38
+
39
+ options.keys { |key| raise Jsoning::Error, "Undefined option: #{key}" }
40
+
41
+ protocol.add_mapper mapper
42
+ end
43
+ end
@@ -0,0 +1,2 @@
1
+ class Jsoning::Error < StandardError
2
+ end
@@ -0,0 +1,73 @@
1
+ # takes care of translating/fetching values from the object
2
+ class Jsoning::Mapper
3
+ # when mapped, what will be the mapped name
4
+ attr_writer :name
5
+
6
+ attr_accessor :default_value
7
+ attr_writer :nullable
8
+ # what variable in the object will be used to obtain the value
9
+ attr_accessor :parallel_variable
10
+ attr_accessor :custom_block
11
+
12
+ def initialize
13
+ self.parallel_variable = nil
14
+ self.default_value = nil
15
+ self.nullable = true
16
+ end
17
+
18
+ def nullable
19
+ if @nullable.is_a?(TrueClass) || @nullable.is_a?(FalseClass)
20
+ return @nullable
21
+ else
22
+ # by default, allow every mapped things to be nil
23
+ true
24
+ end
25
+ end
26
+
27
+ def name
28
+ @name_as_string = @name.to_s if @name_as_string.nil?
29
+ @name_as_string
30
+ end
31
+
32
+ # map this very specific object's field to target_hash
33
+ def extract(object, target_hash)
34
+ if object.respond_to?(parallel_variable)
35
+ parallel_val = object.send(parallel_variable)
36
+ parallel_val = default_value if parallel_val.nil?
37
+ target_hash[name] = deep_parse(parallel_val)
38
+ else
39
+ if default_value
40
+ target_hash[name] = deep_parse(default_value)
41
+ else
42
+ unless nullable
43
+ raise Jsoning::Error, "Null value given for '#{name}' when serializing #{object}"
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ private
50
+ def deep_parse(object)
51
+ parsed_data = nil
52
+
53
+ if object.is_a?(Array)
54
+ parsed_data = []
55
+ object.each do |each_obj|
56
+ parsed_data << deep_parse(each_obj)
57
+ end
58
+ elsif object.is_a?(Hash)
59
+ parsed_data = {}
60
+ object.each do |obj_key_name, obj_val|
61
+ parsed_data[obj_key_name] = deep_parse(obj_val)
62
+ end
63
+ elsif object.is_a?(Integer) || object.is_a?(Float) || object.is_a?(String) ||
64
+ object.is_a?(TrueClass) || object.is_a?(FalseClass) || object.is_a?(NilClass)
65
+ parsed_data = object
66
+ else
67
+ protocol = Jsoning.protocol_for!(object.class)
68
+ parsed_data = protocol.parse(object)
69
+ end
70
+
71
+ parsed_data
72
+ end
73
+ end
@@ -0,0 +1,59 @@
1
+ # takes care of the class
2
+ class Jsoning::Protocol
3
+ attr_reader :klass
4
+ attr_reader :mappers
5
+ attr_reader :mappers_order
6
+
7
+ def initialize(klass)
8
+ @klass = klass
9
+
10
+ # mappers, only storing symbol of mapped values
11
+ @mappers_order = []
12
+
13
+ @mappers = {}
14
+ end
15
+
16
+ def add_mapper(mapper)
17
+ raise Jsoning::Error, "Mapper must be of class Jsoning::Mapper" unless mapper.is_a?(Jsoning::Mapper)
18
+ @mappers_order << canonical_name(mapper.name)
19
+ @mappers[canonical_name(mapper.name)] = mapper
20
+ end
21
+
22
+ def mapper_for(name)
23
+ @mappers[canonical_name(name)]
24
+ end
25
+
26
+ # generate a JSON object
27
+ # options:
28
+ # - pretty: pretty print json data
29
+ def generate(object, options = {})
30
+ pretty = options[:pretty]
31
+ pretty = options["pretty"] if pretty.nil?
32
+ pretty = false if pretty.nil?
33
+
34
+ data = parse(object)
35
+
36
+ if pretty
37
+ JSON.pretty_generate(data)
38
+ else
39
+ JSON.generate(data)
40
+ end
41
+ end
42
+
43
+ def parse(object)
44
+ # hold data here
45
+ data = {}
46
+
47
+ mappers_order.each do |mapper_sym|
48
+ mapper = mapper_for(mapper_sym)
49
+ mapper.extract(object, data)
50
+ end
51
+
52
+ data
53
+ end
54
+
55
+ private
56
+ def canonical_name(key_name)
57
+ key_name.to_s.downcase.to_sym
58
+ end
59
+ end
@@ -0,0 +1,3 @@
1
+ module Jsoning
2
+ VERSION = "0.1.0"
3
+ end
data/lib/jsoning.rb ADDED
@@ -0,0 +1,52 @@
1
+ require "jsoning/version"
2
+
3
+ require "jsoning/dsl/for_dsl"
4
+ require "jsoning/exceptions/error"
5
+ require "jsoning/foundations/mapper"
6
+ require "jsoning/foundations/protocol"
7
+
8
+ require "json"
9
+
10
+ module Jsoning
11
+ PROTOCOLS = {}
12
+
13
+ module_function
14
+
15
+ # returns a protocol, or create one if none exists
16
+ def protocol_for(klass)
17
+ protocol = PROTOCOLS[klass.to_s]
18
+ if protocol.nil?
19
+ protocol = Jsoning::Protocol.new(klass)
20
+ PROTOCOLS[klass.to_s] = protocol
21
+ end
22
+ protocol
23
+ end
24
+
25
+ def protocol_for!(klass)
26
+ protocol = PROTOCOLS[klass.to_s]
27
+ raise Jsoning::Error, "Undefined Jsoning protocol for #{klass.to_s}" if protocol.nil?
28
+ protocol
29
+ end
30
+
31
+ def clear
32
+ PROTOCOLS.clear
33
+ end
34
+
35
+ def for(klass, &block)
36
+ Jsoning::ForDsl.new(protocol_for(klass)).instance_eval(&block)
37
+ end
38
+
39
+ def generate(object, options = {})
40
+ protocol = protocol_for!(object.class)
41
+ protocol.generate(object, options)
42
+ end
43
+
44
+ # monkey patch Kernel
45
+ module ::Kernel
46
+ private
47
+
48
+ def Jsoning(object, options = {})
49
+ Jsoning.generate(object, options)
50
+ end
51
+ end
52
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jsoning
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Adam Pahlevi
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-09-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.3'
55
+ description: |-
56
+ Turning object into json can sometimes be frustrating. With Jsoning, you could turn your
57
+ everyday ruby object into JSON, very easily. It should work with
58
+ any Ruby object there is. Kiss good bye to complexity!
59
+ email:
60
+ - adam.pahlevi@gmail.com
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - ".gitignore"
66
+ - ".rspec"
67
+ - ".travis.yml"
68
+ - CODE_OF_CONDUCT.md
69
+ - Gemfile
70
+ - LICENSE.txt
71
+ - README.md
72
+ - Rakefile
73
+ - bin/console
74
+ - bin/setup
75
+ - jsoning.gemspec
76
+ - lib/jsoning.rb
77
+ - lib/jsoning/dsl/for_dsl.rb
78
+ - lib/jsoning/exceptions/error.rb
79
+ - lib/jsoning/foundations/mapper.rb
80
+ - lib/jsoning/foundations/protocol.rb
81
+ - lib/jsoning/version.rb
82
+ homepage: http://github.com/saveav/jsoning
83
+ licenses:
84
+ - MIT
85
+ metadata: {}
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 2.4.5
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: Turns any of your everyday ruby objects to json formats, the way you always
106
+ want it
107
+ test_files: []
108
+ has_rdoc: