json2 0.1.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,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
+ }