json2 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,70 @@
1
+ module Json2
2
+
3
+ # Turn a Json input into a Csv output without header.
4
+ class CsvWithoutHeader
5
+
6
+ # Creates a new CsvWithoutHeader instance.
7
+ #
8
+ # input - A Hash representing a Json file. This is typically
9
+ # obtained with JSON.parse.
10
+ def initialize(input)
11
+ @input = input
12
+ @names_stack = []
13
+ @output = ''
14
+ process_input
15
+ end
16
+
17
+ # Get the Csv.
18
+ #
19
+ # Returns the whole document as a single String.
20
+ attr_reader :output
21
+
22
+ private
23
+
24
+ def process_input
25
+ process_keys(@input)
26
+ end
27
+
28
+ def process_keys(object)
29
+ if object.respond_to?(:each_key)
30
+ object.each_key do |key|
31
+ @names_stack.push(key)
32
+ process_key(object[key])
33
+ @names_stack.pop
34
+ end
35
+ else
36
+ record_line(object)
37
+ end
38
+ end
39
+
40
+ def process_key(object)
41
+ case object
42
+ when ~:each_key then process_keys(object)
43
+ when ~:at then process_array(object)
44
+ else
45
+ error(99, 'Error, try without using --without-header')
46
+ end
47
+ end
48
+
49
+ def process_array(object)
50
+ if object.empty?
51
+ record_line('')
52
+ else
53
+ object.each {|element| process_keys(element) }
54
+ end
55
+ end
56
+
57
+ def record_line(element)
58
+ @names_stack.push(element)
59
+ @output += @names_stack.join(',') + "\n"
60
+ @names_stack.pop
61
+ end
62
+
63
+ def error(code, message)
64
+ warn(message)
65
+ exit(code)
66
+ end
67
+
68
+ end
69
+
70
+ end
@@ -0,0 +1,36 @@
1
+ module Json2
2
+
3
+ # Build a csv header.
4
+ class Header
5
+
6
+ # Get the header of a Csv file.
7
+ #
8
+ # For a description of the parameter(s) see Header#initialize.
9
+ #
10
+ # Returns the String header, that is a single line with comma
11
+ # separated column's name.
12
+ def self.get(keys)
13
+ new(keys).get
14
+ end
15
+
16
+ # Creates a new Header instance.
17
+ #
18
+ # keys - A Hash of String names of variable/column.
19
+ def initialize(keys)
20
+ @header = []
21
+ @keys = keys
22
+ end
23
+
24
+ # Get the header of a Csv file. See also Header.get.
25
+ #
26
+ # Returns the String header.
27
+ def get
28
+ @keys.each do |key|
29
+ short_name = key.split('.').last
30
+ @header << (@header.include?(short_name) ? key : short_name)
31
+ end
32
+ @header.join(',') + "\n"
33
+ end
34
+ end
35
+
36
+ end
@@ -0,0 +1,75 @@
1
+ module Json2
2
+
3
+ # Process command line switches.
4
+ #
5
+ # The keys you are going to use:
6
+ #
7
+ # :without_header - Boolean, if true the user want to parse the Json
8
+ # file as if it has no header data.
9
+ # :with_path - Boolean, if true the user wants to extract only
10
+ # a particular path in the Json file.
11
+ # :path - This is the String path to extract if :with_path
12
+ # is true.
13
+ #
14
+ # Examples
15
+ #
16
+ # opt = Option.new
17
+ # if opt[:with_path]
18
+ # puts "Extracting #{opt[:path]}…"
19
+ # # Do the job.
20
+ # end
21
+ class Option
22
+
23
+ # Creates a new Option instance.
24
+ def initialize
25
+ @options = { without_header: false, with_path: false }
26
+
27
+ optparse = OptionParser.new {|opts| parse(opts) }
28
+
29
+ begin
30
+ optparse.parse!
31
+ rescue OptionParser::InvalidOption => exception
32
+ puts exception.to_s
33
+ exit 1
34
+ end
35
+
36
+ print_version if @options[:version]
37
+ end
38
+
39
+ # Get an option.
40
+ #
41
+ # key - The Symbol name of the option to get.
42
+ #
43
+ # Returns Any value corresponding of the key, or nil if the key
44
+ # doesn't exists.
45
+ def [](key)
46
+ @options[key]
47
+ end
48
+
49
+ def parse(opts)
50
+ opts.on('-w', '--without-header', 'Output csv without a header') do
51
+ @options[:without_header] = true
52
+ end
53
+ opts.on('-p', '--path PATH', 'Extract only this path') do |arg|
54
+ @options[:with_path] = true
55
+ @options[:path] = arg
56
+ end
57
+ opts.on('-v', '--version', 'Print version number and exit') do
58
+ @options[:version] = true
59
+ end
60
+ opts.on('-h', '--help', 'Display this screen') do
61
+ puts opts
62
+ exit
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def print_version
69
+ puts "Json2 version #{VERSION}"
70
+ exit
71
+ end
72
+
73
+ end
74
+
75
+ end
@@ -0,0 +1,26 @@
1
+ # Simplify the use of duck typing in case/when structure.
2
+ #
3
+ # Examples
4
+ #
5
+ # a = []
6
+ # b = ~:each
7
+ # b.call(a) #=> true
8
+ #
9
+ # # How is this simplification!? Are you kiding me?
10
+ # # We can use it like this:
11
+ #
12
+ # case object
13
+ # when ~:each then …
14
+ # when ~:keys then …
15
+ # else …
16
+ # end
17
+ module SymbolRespondTo
18
+
19
+ # Returns Boolean.
20
+ def ~@
21
+ ->(object) { object.respond_to?(self) }
22
+ end
23
+
24
+ end
25
+
26
+ Symbol.send(:include, SymbolRespondTo)
@@ -0,0 +1,3 @@
1
+ module Json2
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ include Json2
4
+
5
+ describe Body do
6
+ describe '.get' do
7
+ it 'builds a body' do
8
+ nodes = { "color": ["red", "green", "blue"],
9
+ "value": ["#f00", "#0f0", "#00f"] }
10
+ body = Body.get(nodes, nodes.keys, 3)
11
+ expect(body).to eq fake_body
12
+ end
13
+ end
14
+ end
15
+
16
+ def fake_body
17
+ <<END
18
+ red,#f00
19
+ green,#0f0
20
+ blue,#00f
21
+ END
22
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ include Json2
4
+
5
+ describe CsvWithHeader do
6
+
7
+ describe 'when the header is unknown' do
8
+
9
+ it 'exits' do
10
+ expect {
11
+ CsvWithHeader.new(input)
12
+ }.to raise_error(SystemExit)
13
+ end
14
+
15
+ it 'exits with right code' do
16
+ begin
17
+ CsvWithHeader.new(input)
18
+ rescue SystemExit => e
19
+ expect(e.status).to eq 98
20
+ end
21
+ end
22
+
23
+ end
24
+
25
+ def input
26
+ {
27
+ "Nom du parti" => {
28
+ "Abstention" => [
29
+ "Foo1 Bar1"
30
+ ],
31
+ "Non-votant" => [],
32
+ "Contre" => [
33
+ "Foo2 Bar2",
34
+ "Foo3 Bar3"
35
+ ],
36
+ "Pour" => [
37
+ "Foo4 Bar4"
38
+ ]
39
+ }
40
+ }
41
+ end
42
+
43
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ include Json2
4
+
5
+ describe CsvWithoutHeader do
6
+
7
+ describe 'When the header is known' do
8
+
9
+ it 'exits' do
10
+ expect { CsvWithoutHeader.new(input) }.to raise_error(SystemExit)
11
+ end
12
+
13
+ def input
14
+ {
15
+ "red" => "#f00",
16
+ "green" => "#0f0",
17
+ }
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,4 @@
1
+ This directory is full of different kind of Json files.
2
+
3
+ Some examples are adapted from:
4
+ http://adobe.github.io/Spry/samples/data_region/JSONDataSetSample.html
@@ -0,0 +1,30 @@
1
+ [
2
+ {
3
+ "color": "red",
4
+ "value": "#f00"
5
+ },
6
+ {
7
+ "color": "green",
8
+ "value": "#0f0"
9
+ },
10
+ {
11
+ "color": "blue",
12
+ "value": "#00f"
13
+ },
14
+ {
15
+ "color": "cyan",
16
+ "value": "#0ff"
17
+ },
18
+ {
19
+ "color": "magenta",
20
+ "value": "#f0f"
21
+ },
22
+ {
23
+ "color": "yellow",
24
+ "value": "#ff0"
25
+ },
26
+ {
27
+ "color": "black",
28
+ "value": "#000"
29
+ }
30
+ ]
@@ -0,0 +1,33 @@
1
+ {
2
+ "colors":
3
+ [
4
+ {
5
+ "color": "red",
6
+ "value": "#f00"
7
+ },
8
+ {
9
+ "color": "green",
10
+ "value": "#0f0"
11
+ },
12
+ {
13
+ "color": "blue",
14
+ "value": "#00f"
15
+ },
16
+ {
17
+ "color": "cyan",
18
+ "value": "#0ff"
19
+ },
20
+ {
21
+ "color": "magenta",
22
+ "value": "#f0f"
23
+ },
24
+ {
25
+ "color": "yellow",
26
+ "value": "#ff0"
27
+ },
28
+ {
29
+ "color": "black",
30
+ "value": "#000"
31
+ }
32
+ ]
33
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "colorsArray":[{
3
+ "red":"#f00",
4
+ "green":"#0f0",
5
+ "blue":"#00f",
6
+ "cyan":"#0ff",
7
+ "magenta":"#f0f",
8
+ "yellow":"#ff0",
9
+ "black":"#000"
10
+ }
11
+ ]
12
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "red":"#f00",
3
+ "green":"#0f0",
4
+ "blue":"#00f",
5
+ "cyan":"#0ff",
6
+ "magenta":"#f0f",
7
+ "yellow":"#ff0",
8
+ "black":"#000"
9
+ }
@@ -0,0 +1,43 @@
1
+ {
2
+ "login": "lkdjiin",
3
+ "id": 498017,
4
+ "avatar_url": "https://avatars.githubusercontent.com/u/498017?v=3",
5
+ "gravatar_id": "",
6
+ "url": "https://api.github.com/users/lkdjiin",
7
+ "html_url": "https://github.com/lkdjiin",
8
+ "followers_url": "https://api.github.com/users/lkdjiin/followers",
9
+ "following_url": "https://api.github.com/users/lkdjiin/following{/other_user}",
10
+ "gists_url": "https://api.github.com/users/lkdjiin/gists{/gist_id}",
11
+ "starred_url": "https://api.github.com/users/lkdjiin/starred{/owner}{/repo}",
12
+ "subscriptions_url": "https://api.github.com/users/lkdjiin/subscriptions",
13
+ "organizations_url": "https://api.github.com/users/lkdjiin/orgs",
14
+ "repos_url": "https://api.github.com/users/lkdjiin/repos",
15
+ "events_url": "https://api.github.com/users/lkdjiin/events{/privacy}",
16
+ "received_events_url": "https://api.github.com/users/lkdjiin/received_events",
17
+ "type": "User",
18
+ "site_admin": false,
19
+ "name": "Xavier Nayrac",
20
+ "company": "",
21
+ "blog": "http://lkdjiin.github.io",
22
+ "location": "reims france",
23
+ "email": "xavier.nayrac@gmail.com",
24
+ "hireable": true,
25
+ "bio": null,
26
+ "public_repos": 70,
27
+ "public_gists": 2,
28
+ "followers": 14,
29
+ "following": 0,
30
+ "created_at": "2010-11-26T15:35:49Z",
31
+ "updated_at": "2015-05-15T12:50:44Z",
32
+ "private_gists": 0,
33
+ "total_private_repos": 0,
34
+ "owned_private_repos": 0,
35
+ "disk_usage": 192692,
36
+ "collaborators": 0,
37
+ "plan": {
38
+ "name": "free",
39
+ "space": 976562499,
40
+ "collaborators": 0,
41
+ "private_repos": 0
42
+ }
43
+ }