yinspire 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.
- data/README +24 -0
- data/bench/pq/Makefile +5 -0
- data/bench/pq/bench.cc +321 -0
- data/bench/pq/bench.rb +125 -0
- data/bench/pq/bench_binaryheap.h +46 -0
- data/bench/pq/bench_calendarqueue.h +58 -0
- data/bench/pq/bench_pairingheap.h +61 -0
- data/bench/pq/bench_stlpq.h +46 -0
- data/bench/pq/benchmark.h +225 -0
- data/bench/pq/distribution.h +93 -0
- data/bench/pq/make.rb +24 -0
- data/bin/yinspire +186 -0
- data/examples/nets/gereon2005.c.json +93723 -0
- data/examples/nets/gereon2005.yin +232650 -0
- data/examples/nets/skorpion.graphml +396 -0
- data/examples/nets/spiketrains_angle_180.txt +8 -0
- data/lib/Algorithms/Array.h +52 -0
- data/lib/Algorithms/BinaryHeap.h +265 -0
- data/lib/Algorithms/CalendarQueue.h +257 -0
- data/lib/Algorithms/IndexedBinaryHeap.h +90 -0
- data/lib/Algorithms/PairingHeap.h +169 -0
- data/lib/Allocators/ChunkedFreelistAllocator.h +96 -0
- data/lib/Allocators/MemoryAllocator.h +45 -0
- data/lib/Allocators/RubyMemoryAllocator.h +37 -0
- data/lib/Yinspire.rb +69 -0
- data/lib/Yinspire/All.rb +10 -0
- data/lib/Yinspire/Core/NeuralEntity.rb +133 -0
- data/lib/Yinspire/Core/Neuron.rb +162 -0
- data/lib/Yinspire/Core/Scheduling/NeuralEntity.rb +123 -0
- data/lib/Yinspire/Core/Scheduling/Simulator.rb +94 -0
- data/lib/Yinspire/Core/Simulator.rb +36 -0
- data/lib/Yinspire/Core/StimuliMixin.rb +103 -0
- data/lib/Yinspire/Core/Stimulus.rb +25 -0
- data/lib/Yinspire/Core/Synapse.rb +64 -0
- data/lib/Yinspire/Dumpers/Dumper.rb +19 -0
- data/lib/Yinspire/Dumpers/Dumper_Dot.rb +28 -0
- data/lib/Yinspire/Loaders/GraphML.rb +84 -0
- data/lib/Yinspire/Loaders/Loader.rb +31 -0
- data/lib/Yinspire/Loaders/Loader_GraphML.rb +97 -0
- data/lib/Yinspire/Loaders/Loader_JSON.rb +181 -0
- data/lib/Yinspire/Loaders/Loader_Spike.rb +42 -0
- data/lib/Yinspire/Loaders/Loader_Yin.rb +62 -0
- data/lib/Yinspire/Loaders/YinScanner.rb +247 -0
- data/lib/Yinspire/Models/Neuron_Base.rb +38 -0
- data/lib/Yinspire/Models/Neuron_Input.rb +12 -0
- data/lib/Yinspire/Models/Neuron_InputOutput.rb +39 -0
- data/lib/Yinspire/Models/Neuron_Output.rb +15 -0
- data/lib/Yinspire/Models/Neuron_SRM01.rb +50 -0
- data/lib/Yinspire/Models/Neuron_SRM02.rb +64 -0
- data/lib/Yinspire/Models/Synapse_Hebb.rb +67 -0
- data/pure_cpp/Makefile +22 -0
- data/pure_cpp/README +2 -0
- data/pure_cpp/src/algo/binary_heap.h +277 -0
- data/pure_cpp/src/algo/indexed_binary_heap.h +90 -0
- data/pure_cpp/src/json/json.cc +542 -0
- data/pure_cpp/src/json/json.h +182 -0
- data/pure_cpp/src/json/json_parser.cc +685 -0
- data/pure_cpp/src/json/json_parser.h +15 -0
- data/pure_cpp/src/json/json_parser.rl +213 -0
- data/pure_cpp/src/main.cc +49 -0
- data/pure_cpp/src/memory_allocator.h +45 -0
- data/pure_cpp/src/neural_entity.cc +208 -0
- data/pure_cpp/src/neural_entity.h +243 -0
- data/pure_cpp/src/neuron.cc +136 -0
- data/pure_cpp/src/neuron.h +70 -0
- data/pure_cpp/src/neuron_srm_01.cc +77 -0
- data/pure_cpp/src/neuron_srm_01.h +36 -0
- data/pure_cpp/src/simulator.cc +151 -0
- data/pure_cpp/src/simulator.h +116 -0
- data/pure_cpp/src/synapse.cc +117 -0
- data/pure_cpp/src/synapse.h +60 -0
- data/pure_cpp/src/types.h +18 -0
- data/run.rb +68 -0
- data/tools/conv_jsonc_to_yin.rb +165 -0
- data/tools/converter.rb +93 -0
- data/tools/json_writer.rb +122 -0
- data/yinspire.gemspec +20 -0
- metadata +156 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
#ifndef __YINSPIRE__SYNAPSE__
|
2
|
+
#define __YINSPIRE__SYNAPSE__
|
3
|
+
|
4
|
+
#include "neural_entity.h"
|
5
|
+
|
6
|
+
class Neuron; // forward declaration
|
7
|
+
|
8
|
+
class Synapse : public NeuralEntity
|
9
|
+
{
|
10
|
+
friend class Neuron;
|
11
|
+
typedef NeuralEntity super;
|
12
|
+
|
13
|
+
protected:
|
14
|
+
|
15
|
+
/*
|
16
|
+
* The fire weight of a Synapse.
|
17
|
+
*/
|
18
|
+
real weight;
|
19
|
+
|
20
|
+
/*
|
21
|
+
* The propagation delay of a Synapse.
|
22
|
+
*/
|
23
|
+
simtime delay;
|
24
|
+
|
25
|
+
/*
|
26
|
+
* The pre and post Neurons of the Synapse.
|
27
|
+
*/
|
28
|
+
Neuron *pre_neuron;
|
29
|
+
Neuron *post_neuron;
|
30
|
+
|
31
|
+
/*
|
32
|
+
* Those two pointers are part of an internal linked-list that
|
33
|
+
* starts at a Neuron and connects all pre-synapses of an Neuron
|
34
|
+
* together. In the same way it connects all post-synapses of an
|
35
|
+
* Neuron together.
|
36
|
+
*/
|
37
|
+
Synapse *next_pre_synapse;
|
38
|
+
Synapse *next_post_synapse;
|
39
|
+
|
40
|
+
public:
|
41
|
+
|
42
|
+
/*
|
43
|
+
* Constructor
|
44
|
+
*/
|
45
|
+
Synapse();
|
46
|
+
|
47
|
+
public:
|
48
|
+
|
49
|
+
virtual void dump(jsonHash *into);
|
50
|
+
virtual void load(jsonHash *data);
|
51
|
+
|
52
|
+
virtual void stimulate(simtime at, real weight, NeuralEntity *source);
|
53
|
+
virtual void connect(NeuralEntity *target);
|
54
|
+
virtual void disconnect(NeuralEntity *target);
|
55
|
+
virtual void each_connection(
|
56
|
+
void (*yield)(NeuralEntity *self, NeuralEntity *conn));
|
57
|
+
|
58
|
+
};
|
59
|
+
|
60
|
+
#endif
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#ifndef __YINSPIRE__TYPES__
|
2
|
+
#define __YINSPIRE__TYPES__
|
3
|
+
|
4
|
+
typedef unsigned int uint;
|
5
|
+
typedef float real;
|
6
|
+
typedef float simtime;
|
7
|
+
|
8
|
+
#define real_exp expf
|
9
|
+
#define real_fabs fabsf
|
10
|
+
|
11
|
+
#ifndef NULL
|
12
|
+
#define NULL 0L
|
13
|
+
#endif
|
14
|
+
|
15
|
+
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
16
|
+
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
17
|
+
|
18
|
+
#endif
|
data/run.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
$LOAD_PATH.unshift "lib"
|
3
|
+
|
4
|
+
require 'Yinspire'
|
5
|
+
require 'Yinspire/Models/Neuron_Input'
|
6
|
+
require 'Yinspire/Models/Neuron_Output'
|
7
|
+
require 'Yinspire/Models/Neuron_SRM01'
|
8
|
+
require 'Yinspire/Models/Neuron_SRM02'
|
9
|
+
require 'Yinspire/Models/Synapse_Hebb'
|
10
|
+
require 'Yinspire/Loaders/Loader_JSON'
|
11
|
+
require 'Yinspire/Loaders/Loader_GraphML'
|
12
|
+
require 'Yinspire/Loaders/Loader_Yin'
|
13
|
+
|
14
|
+
def example_net(sim, n)
|
15
|
+
inputs = (0...n).map {|i|
|
16
|
+
Neuron_Input.new("inp_#{i}", sim)
|
17
|
+
}
|
18
|
+
|
19
|
+
outputs = (0...n).map {|i|
|
20
|
+
Neuron_Output.new("out_#{i}", sim)
|
21
|
+
}
|
22
|
+
|
23
|
+
synapses = (0...n).map {|i|
|
24
|
+
Synapse.new("syn_#{i}", sim) {|s|
|
25
|
+
s.delay = 0.4
|
26
|
+
s.weight = 10.0
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
(0...n).each {|i|
|
31
|
+
inputs[i].connect(synapses[i])
|
32
|
+
synapses[i].connect(outputs[i])
|
33
|
+
}
|
34
|
+
|
35
|
+
(0...n).each {|i|
|
36
|
+
inputs[i].stimulate(0.0+i, 1.0, nil)
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
Yinspire.commit('./work/Yinspire')
|
41
|
+
|
42
|
+
sim = Simulator.new
|
43
|
+
sim.stimuli_tolerance = 0.0
|
44
|
+
|
45
|
+
class Neuron_Output
|
46
|
+
def fire(at, weight)
|
47
|
+
puts "#{id()}\t#{at}\t#{weight}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
#loader = Loader_GraphML.new(sim)
|
52
|
+
#loader.load('examples/nets/skorpion.graphml')
|
53
|
+
|
54
|
+
#loader = Loader_JSON.new(sim)
|
55
|
+
#loader.load('/tmp/gereon2005.json')
|
56
|
+
|
57
|
+
loader = Loader_Yin.new(sim)
|
58
|
+
loader.load('./examples/nets/gereon2005.yin')
|
59
|
+
|
60
|
+
#require 'pp'
|
61
|
+
#pp loader.dump_entities
|
62
|
+
#example_net(sim, 10_000)
|
63
|
+
|
64
|
+
stop_at = ARGV[0].to_f
|
65
|
+
puts "stop_at: #{stop_at}"
|
66
|
+
sim.run(stop_at)
|
67
|
+
puts "events: #{sim.event_counter}"
|
68
|
+
puts "fires: #{sim.fire_counter}"
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'enumerator'
|
3
|
+
|
4
|
+
class String
|
5
|
+
def to_yin_str
|
6
|
+
if self =~ /^\w+$/
|
7
|
+
self
|
8
|
+
else
|
9
|
+
'"' + self + '"'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class TrueClass; alias to_yin_str to_s end
|
15
|
+
class FalseClass; alias to_yin_str to_s end
|
16
|
+
class Float; alias to_yin_str to_s end
|
17
|
+
class Fixnum; alias to_yin_str to_s end
|
18
|
+
class Bignum; alias to_yin_str to_s end
|
19
|
+
|
20
|
+
class Hash
|
21
|
+
def to_yin_str(out="")
|
22
|
+
out << "{\n"
|
23
|
+
self.keys.sort.each do |k|
|
24
|
+
out << " " if $verbose
|
25
|
+
out << "#{k.to_yin_str} = #{self[k].to_yin_str}\n"
|
26
|
+
end
|
27
|
+
out << "}\n"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
data = YAML.load(STDIN.read)
|
32
|
+
out = STDOUT
|
33
|
+
$verbose = true
|
34
|
+
|
35
|
+
raise unless data['format'] == 'yinspire.c'
|
36
|
+
|
37
|
+
#data['entities'] = nil
|
38
|
+
#data['templates'] = nil
|
39
|
+
#data['connections'] = nil
|
40
|
+
|
41
|
+
#
|
42
|
+
# Write out templates
|
43
|
+
#
|
44
|
+
|
45
|
+
templates = data["templates"] || {}
|
46
|
+
if $verbose and !templates.empty?
|
47
|
+
out << "#\n"
|
48
|
+
out << "# Templates\n"
|
49
|
+
out << "#\n\n"
|
50
|
+
end
|
51
|
+
|
52
|
+
templates.keys.sort.each do |key|
|
53
|
+
base_type, base_data = *templates[key]
|
54
|
+
|
55
|
+
out << "TEMPLATE " if $verbose
|
56
|
+
out << "#{key.to_yin_str} < #{base_type.to_yin_str}"
|
57
|
+
if base_data and not base_data.empty?
|
58
|
+
out << " "
|
59
|
+
base_data.to_yin_str(out)
|
60
|
+
else
|
61
|
+
out << "\n"
|
62
|
+
end
|
63
|
+
out << "\n" if $verbose
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
#
|
68
|
+
# Write out entities
|
69
|
+
#
|
70
|
+
|
71
|
+
entities = data["entities"] || []
|
72
|
+
if $verbose and !entities.empty?
|
73
|
+
out << "#\n"
|
74
|
+
out << "# Entities\n"
|
75
|
+
out << "#\n\n"
|
76
|
+
end
|
77
|
+
|
78
|
+
group_by = {}
|
79
|
+
entities.each do |id, type, edata|
|
80
|
+
key = [type, edata]
|
81
|
+
group_by[key] ||= []
|
82
|
+
group_by[key] << id
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
group_by.keys.sort_by {|type, _| type}.each do |key|
|
87
|
+
type, edata = *key
|
88
|
+
ids = group_by[key]
|
89
|
+
out << "ENTITY " if $verbose
|
90
|
+
out << ids.sort.map {|id| id.to_yin_str}.enum_for(:each_slice, 8).map {|sl|
|
91
|
+
sl.join(", ")
|
92
|
+
}.join(",\n ")
|
93
|
+
|
94
|
+
out << " = #{ type.to_yin_str }"
|
95
|
+
|
96
|
+
|
97
|
+
if edata and not edata.empty?
|
98
|
+
out << " "
|
99
|
+
edata.to_yin_str(out)
|
100
|
+
else
|
101
|
+
out << "\n"
|
102
|
+
end
|
103
|
+
out << "\n" if $verbose
|
104
|
+
end
|
105
|
+
|
106
|
+
#
|
107
|
+
# Write out connections
|
108
|
+
#
|
109
|
+
|
110
|
+
connections = data["connections"] || []
|
111
|
+
if $verbose and !connections.empty?
|
112
|
+
out << "#\n"
|
113
|
+
out << "# Connections\n"
|
114
|
+
out << "#\n\n"
|
115
|
+
end
|
116
|
+
|
117
|
+
connections.each do |arr|
|
118
|
+
src, *targets = *arr
|
119
|
+
out << "CONNECT " if $verbose
|
120
|
+
out << "#{src.to_yin_str} -> "
|
121
|
+
|
122
|
+
out << targets.map {|t| t.to_yin_str}.enum_for(:each_slice, 8).map {|sl|
|
123
|
+
sl.join(", ")
|
124
|
+
}.join(",\n ")
|
125
|
+
out << "\n"
|
126
|
+
|
127
|
+
out << "\n" if $verbose
|
128
|
+
end
|
129
|
+
|
130
|
+
#
|
131
|
+
# Write out stimuli
|
132
|
+
#
|
133
|
+
|
134
|
+
events = data["events"] || {}
|
135
|
+
if $verbose and !events.empty?
|
136
|
+
out << "#\n"
|
137
|
+
out << "# Stimulations\n"
|
138
|
+
out << "#\n\n"
|
139
|
+
end
|
140
|
+
|
141
|
+
events.keys.sort.each do |key|
|
142
|
+
ev = events[key]
|
143
|
+
next if ev.empty?
|
144
|
+
|
145
|
+
out << "STIMULATE " if $verbose
|
146
|
+
out << "#{key.to_yin_str} ! {\n"
|
147
|
+
|
148
|
+
out << " "
|
149
|
+
char_pos = 1
|
150
|
+
|
151
|
+
ev.each do |e|
|
152
|
+
str = e.to_yin_str
|
153
|
+
if char_pos > 40 && char_pos+str.size > 75
|
154
|
+
out << "\n "
|
155
|
+
char_pos = 1
|
156
|
+
end
|
157
|
+
out << " "
|
158
|
+
out << str
|
159
|
+
char_pos += 1 + str.size
|
160
|
+
end
|
161
|
+
|
162
|
+
out << "\n}\n"
|
163
|
+
|
164
|
+
out << "\n" if $verbose
|
165
|
+
end
|
data/tools/converter.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'json_writer'
|
3
|
+
|
4
|
+
# format changes:
|
5
|
+
#
|
6
|
+
# * neuron/synapse type names changed
|
7
|
+
# * property names changed
|
8
|
+
# * no longer post_neuron, pre_neuron, instead connections.
|
9
|
+
#
|
10
|
+
|
11
|
+
old = YAML.load(File.read('/tmp/gereon2005'))
|
12
|
+
new = {}
|
13
|
+
new['format'] = 'yinspire.1'
|
14
|
+
new['templates'] = {}
|
15
|
+
entities = new['entities'] = {}
|
16
|
+
connections = new['connections'] = {}
|
17
|
+
new['events'] = old['events']
|
18
|
+
|
19
|
+
#
|
20
|
+
# convert templates
|
21
|
+
#
|
22
|
+
old['templates'].each do |name, hash|
|
23
|
+
|
24
|
+
type =
|
25
|
+
case hash.delete("type")
|
26
|
+
when 'Synapse_Default' then 'Synapse'
|
27
|
+
when 'Neuron_KernelBasedLIF' then 'Neuron_SRM_01'
|
28
|
+
else
|
29
|
+
raise
|
30
|
+
end
|
31
|
+
|
32
|
+
if abs_ref_duration = hash.delete('abs_ref_duration')
|
33
|
+
hash['abs_refr_duration'] = abs_ref_duration
|
34
|
+
end
|
35
|
+
|
36
|
+
new['templates'][name] = [type, hash]
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
#
|
42
|
+
# convert entities and connections
|
43
|
+
#
|
44
|
+
old['net'].each do |hash|
|
45
|
+
template = hash.delete('_')
|
46
|
+
post_neuron = hash.delete('post_neuron')
|
47
|
+
pre_neuron = hash.delete('pre_neuron')
|
48
|
+
id = hash.delete('id') || raise
|
49
|
+
|
50
|
+
if post_neuron
|
51
|
+
connections[id] ||= []
|
52
|
+
connections[id] << post_neuron
|
53
|
+
end
|
54
|
+
|
55
|
+
if pre_neuron
|
56
|
+
connections[pre_neuron] ||= []
|
57
|
+
connections[pre_neuron] << id
|
58
|
+
end
|
59
|
+
|
60
|
+
if hash.empty?
|
61
|
+
entities[id] = template
|
62
|
+
else
|
63
|
+
entities[id] = [template, hash]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# new2 is efficient for jsonParser/jsonHash which
|
68
|
+
# is implemented as a linked list.
|
69
|
+
def to_new2(new)
|
70
|
+
new2 = Hash.new
|
71
|
+
new2['format'] = 'yinspire.2'
|
72
|
+
new2['templates'] = new['templates']
|
73
|
+
entities = new2['entities'] = []
|
74
|
+
connections = new2['connections'] = []
|
75
|
+
new['entities'].keys.sort.each do |id|
|
76
|
+
v = new['entities'][id]
|
77
|
+
entities << [id, v].flatten
|
78
|
+
end
|
79
|
+
|
80
|
+
new['connections'].keys.sort.each do |from|
|
81
|
+
to = new['connections'][from]
|
82
|
+
#|from, to|
|
83
|
+
connections << [from, to].flatten
|
84
|
+
end
|
85
|
+
|
86
|
+
new2['events'] = new['events']
|
87
|
+
|
88
|
+
return new2
|
89
|
+
end
|
90
|
+
|
91
|
+
#puts YAML.dump(new)
|
92
|
+
#new = to_new2(new)
|
93
|
+
json_pp(new)
|
@@ -0,0 +1,122 @@
|
|
1
|
+
#
|
2
|
+
# Pretty print Ruby objects as JSON
|
3
|
+
#
|
4
|
+
# Copyright (c) 2007 by Michael Neumann (mneumann@ntecs.de)
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'prettyprint'
|
8
|
+
|
9
|
+
class Hash
|
10
|
+
def to_json(pp)
|
11
|
+
ks = keys
|
12
|
+
pp.group(1, '{', '}') {
|
13
|
+
ks.each_with_index do |k, i|
|
14
|
+
v = self[k]
|
15
|
+
|
16
|
+
pp.group {
|
17
|
+
pp.text k.to_s.to_json(true)
|
18
|
+
pp.text ':'
|
19
|
+
pp.group(1) {
|
20
|
+
pp.breakable ' '
|
21
|
+
case v
|
22
|
+
when Hash, Array
|
23
|
+
v.to_json(pp)
|
24
|
+
else
|
25
|
+
pp.text v.to_json
|
26
|
+
end
|
27
|
+
}
|
28
|
+
|
29
|
+
if i < ks.size-1
|
30
|
+
pp.text ","
|
31
|
+
pp.breakable
|
32
|
+
end
|
33
|
+
}
|
34
|
+
end
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Array
|
40
|
+
def to_json(pp)
|
41
|
+
pp.group(1, "[", "]") {
|
42
|
+
each_with_index do |v, i|
|
43
|
+
pp.group {
|
44
|
+
case v
|
45
|
+
when Hash, Array
|
46
|
+
v.to_json(pp)
|
47
|
+
else
|
48
|
+
pp.text v.to_json
|
49
|
+
end
|
50
|
+
|
51
|
+
if i < size()-1
|
52
|
+
pp.text ","
|
53
|
+
pp.breakable ' '
|
54
|
+
end
|
55
|
+
}
|
56
|
+
end
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class TrueClass
|
62
|
+
TRUE = "true".freeze
|
63
|
+
def to_json
|
64
|
+
TRUE
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class FalseClass
|
69
|
+
FALSE = "false".freeze
|
70
|
+
def to_json
|
71
|
+
FALSE
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class NilClass
|
76
|
+
NULL = "null".freeze
|
77
|
+
def to_json
|
78
|
+
NULL
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class Fixnum
|
83
|
+
alias to_json to_s
|
84
|
+
end
|
85
|
+
|
86
|
+
class Bignum
|
87
|
+
alias to_json to_s
|
88
|
+
end
|
89
|
+
|
90
|
+
class Float
|
91
|
+
alias to_json to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
class String
|
95
|
+
def to_json(label=false)
|
96
|
+
label = false # FIXME
|
97
|
+
if label and self =~ /^[A-Za-z_][A-Za-z0-9_]*$/
|
98
|
+
self
|
99
|
+
else
|
100
|
+
inspect
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class Symbol
|
106
|
+
def to_json(label=false)
|
107
|
+
to_s.to_json(label)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def json_pp(obj, out=STDOUT, width=79)
|
112
|
+
case obj
|
113
|
+
when Array, Hash
|
114
|
+
q = PrettyPrint.new(out, width)
|
115
|
+
obj.to_json(q)
|
116
|
+
q.flush
|
117
|
+
else
|
118
|
+
out << obj.to_json
|
119
|
+
end
|
120
|
+
out << "\n"
|
121
|
+
return out
|
122
|
+
end
|