json_pure 1.0.0 → 1.4.6
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/CHANGES +155 -1
- data/COPYING +58 -0
- data/GPL +7 -7
- data/README +324 -45
- data/Rakefile +166 -124
- data/TODO +1 -1
- data/VERSION +1 -1
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log +52 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat +900 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat +901 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log +261 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log +262 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log +82 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log +34 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat +900 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat +901 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log +81 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log +82 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log +82 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log +82 -0
- data/benchmarks/generator2_benchmark.rb +222 -0
- data/benchmarks/generator_benchmark.rb +224 -0
- data/benchmarks/ohai.json +1216 -0
- data/benchmarks/ohai.ruby +1 -0
- data/benchmarks/parser2_benchmark.rb +251 -0
- data/benchmarks/parser_benchmark.rb +259 -0
- data/bin/edit_json.rb +1 -3
- data/bin/prettify_json.rb +75 -0
- data/data/index.html +5 -4
- data/data/prototype.js +2764 -1095
- data/ext/json/ext/generator/extconf.rb +14 -3
- data/ext/json/ext/generator/generator.c +1022 -334
- data/ext/json/ext/generator/generator.h +197 -0
- data/ext/json/ext/parser/extconf.rb +9 -3
- data/ext/json/ext/parser/parser.c +961 -577
- data/ext/json/ext/parser/parser.h +71 -0
- data/ext/json/ext/parser/parser.rl +400 -123
- data/install.rb +0 -0
- data/lib/json/add/core.rb +148 -0
- data/lib/json/add/rails.rb +58 -0
- data/lib/json/common.rb +254 -47
- data/lib/json/editor.rb +236 -72
- data/lib/json/ext.rb +2 -0
- data/lib/json/pure/generator.rb +235 -117
- data/lib/json/pure/parser.rb +124 -25
- data/lib/json/pure.rb +5 -3
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +2 -197
- data/tests/fixtures/fail18.json +1 -0
- data/tests/test_json.rb +181 -22
- data/tests/test_json_addition.rb +84 -16
- data/tests/test_json_encoding.rb +68 -0
- data/tests/test_json_fixtures.rb +9 -5
- data/tests/test_json_generate.rb +114 -14
- data/tests/test_json_rails.rb +144 -0
- data/tests/test_json_unicode.rb +35 -14
- data/tools/fuzz.rb +13 -7
- data/tools/server.rb +0 -1
- metadata +156 -122
- data/benchmarks/benchmark.txt +0 -133
- data/benchmarks/benchmark_generator.rb +0 -44
- data/benchmarks/benchmark_parser.rb +0 -22
- data/benchmarks/benchmark_rails.rb +0 -26
- data/ext/json/ext/generator/Makefile +0 -149
- data/ext/json/ext/generator/unicode.c +0 -184
- data/ext/json/ext/generator/unicode.h +0 -40
- data/ext/json/ext/parser/Makefile +0 -149
- data/ext/json/ext/parser/unicode.c +0 -156
- data/ext/json/ext/parser/unicode.h +0 -44
- data/tests/fixtures/pass18.json +0 -1
- data/tests/runner.rb +0 -24
- /data/tests/fixtures/{fail15.json → pass15.json} +0 -0
- /data/tests/fixtures/{fail16.json → pass16.json} +0 -0
- /data/tests/fixtures/{fail17.json → pass17.json} +0 -0
- /data/tests/fixtures/{fail26.json → pass26.json} +0 -0
data/lib/json/editor.rb
CHANGED
|
@@ -5,6 +5,7 @@ require 'gtk2'
|
|
|
5
5
|
require 'iconv'
|
|
6
6
|
require 'json'
|
|
7
7
|
require 'rbconfig'
|
|
8
|
+
require 'open-uri'
|
|
8
9
|
|
|
9
10
|
module JSON
|
|
10
11
|
module Editor
|
|
@@ -25,6 +26,15 @@ module JSON
|
|
|
25
26
|
# The Nodes necessary for the tree representation of a JSON document
|
|
26
27
|
ALL_NODES = (ALL_TYPES + %w[Key]).sort
|
|
27
28
|
|
|
29
|
+
DEFAULT_DIALOG_KEY_PRESS_HANDLER = lambda do |dialog, event|
|
|
30
|
+
case event.keyval
|
|
31
|
+
when Gdk::Keyval::GDK_Return
|
|
32
|
+
dialog.response Dialog::RESPONSE_ACCEPT
|
|
33
|
+
when Gdk::Keyval::GDK_Escape
|
|
34
|
+
dialog.response Dialog::RESPONSE_REJECT
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
28
38
|
# Returns the Gdk::Pixbuf of the icon named _name_ from the icon cache.
|
|
29
39
|
def Editor.fetch_icon(name)
|
|
30
40
|
@icon_cache ||= {}
|
|
@@ -41,11 +51,13 @@ module JSON
|
|
|
41
51
|
dialog = MessageDialog.new(window, Dialog::MODAL,
|
|
42
52
|
MessageDialog::ERROR,
|
|
43
53
|
MessageDialog::BUTTONS_CLOSE, text)
|
|
54
|
+
dialog.show_all
|
|
44
55
|
dialog.run
|
|
45
56
|
rescue TypeError
|
|
46
57
|
dialog = MessageDialog.new(Editor.window, Dialog::MODAL,
|
|
47
58
|
MessageDialog::ERROR,
|
|
48
59
|
MessageDialog::BUTTONS_CLOSE, text)
|
|
60
|
+
dialog.show_all
|
|
49
61
|
dialog.run
|
|
50
62
|
ensure
|
|
51
63
|
dialog.destroy if dialog
|
|
@@ -58,6 +70,7 @@ module JSON
|
|
|
58
70
|
dialog = MessageDialog.new(window, Dialog::MODAL,
|
|
59
71
|
MessageDialog::QUESTION,
|
|
60
72
|
MessageDialog::BUTTONS_YES_NO, text)
|
|
73
|
+
dialog.show_all
|
|
61
74
|
dialog.run do |response|
|
|
62
75
|
return Gtk::Dialog::RESPONSE_YES === response
|
|
63
76
|
end
|
|
@@ -68,6 +81,7 @@ module JSON
|
|
|
68
81
|
# Convert the tree model starting from Gtk::TreeIter _iter_ into a Ruby
|
|
69
82
|
# data structure and return it.
|
|
70
83
|
def Editor.model2data(iter)
|
|
84
|
+
return nil if iter.nil?
|
|
71
85
|
case iter.type
|
|
72
86
|
when 'Hash'
|
|
73
87
|
hash = {}
|
|
@@ -214,9 +228,18 @@ module JSON
|
|
|
214
228
|
# Adds a Gtk::MenuItem to this instance's #menu. _label_ is the label
|
|
215
229
|
# string, _klass_ is the item type, and _callback_ is the procedure, that
|
|
216
230
|
# is called if the _item_ is activated.
|
|
217
|
-
def add_item(label, klass = MenuItem, &callback)
|
|
231
|
+
def add_item(label, keyval = nil, klass = MenuItem, &callback)
|
|
232
|
+
label = "#{label} (C-#{keyval.chr})" if keyval
|
|
218
233
|
item = klass.new(label)
|
|
219
234
|
item.signal_connect(:activate, &callback)
|
|
235
|
+
if keyval
|
|
236
|
+
self.signal_connect(:'key-press-event') do |item, event|
|
|
237
|
+
if event.state & Gdk::Window::ModifierType::CONTROL_MASK != 0 and
|
|
238
|
+
event.keyval == keyval
|
|
239
|
+
callback.call item
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
end
|
|
220
243
|
menu.append item
|
|
221
244
|
item
|
|
222
245
|
end
|
|
@@ -432,18 +455,18 @@ module JSON
|
|
|
432
455
|
|
|
433
456
|
# Create the menu.
|
|
434
457
|
def create
|
|
435
|
-
add_item("Change node", &method(:change_node))
|
|
458
|
+
add_item("Change node", ?n, &method(:change_node))
|
|
436
459
|
add_separator
|
|
437
|
-
add_item("Cut node", &method(:cut_node))
|
|
438
|
-
add_item("Copy node", &method(:copy_node))
|
|
439
|
-
add_item("Paste node (appending)", &method(:paste_node_appending))
|
|
440
|
-
add_item("Paste node (inserting before)",
|
|
460
|
+
add_item("Cut node", ?X, &method(:cut_node))
|
|
461
|
+
add_item("Copy node", ?C, &method(:copy_node))
|
|
462
|
+
add_item("Paste node (appending)", ?A, &method(:paste_node_appending))
|
|
463
|
+
add_item("Paste node (inserting before)", ?I,
|
|
441
464
|
&method(:paste_node_inserting_before))
|
|
442
465
|
add_separator
|
|
443
|
-
add_item("Append new node", &method(:append_new_node))
|
|
444
|
-
add_item("Insert new node before", &method(:insert_new_node))
|
|
466
|
+
add_item("Append new node", ?a, &method(:append_new_node))
|
|
467
|
+
add_item("Insert new node before", ?i, &method(:insert_new_node))
|
|
445
468
|
add_separator
|
|
446
|
-
add_item("Collapse/Expand node (recursively)",
|
|
469
|
+
add_item("Collapse/Expand node (recursively)", ?e,
|
|
447
470
|
&method(:collapse_expand))
|
|
448
471
|
|
|
449
472
|
menu.show_all
|
|
@@ -474,6 +497,10 @@ module JSON
|
|
|
474
497
|
window.file_open
|
|
475
498
|
end
|
|
476
499
|
|
|
500
|
+
def open_location(item)
|
|
501
|
+
window.location_open
|
|
502
|
+
end
|
|
503
|
+
|
|
477
504
|
# Revert the current JSON document in the editor to the saved version.
|
|
478
505
|
def revert(item)
|
|
479
506
|
window.instance_eval do
|
|
@@ -501,13 +528,14 @@ module JSON
|
|
|
501
528
|
title = MenuItem.new('File')
|
|
502
529
|
title.submenu = menu
|
|
503
530
|
add_item('New', &method(:new))
|
|
504
|
-
add_item('Open', &method(:open))
|
|
531
|
+
add_item('Open', ?o, &method(:open))
|
|
532
|
+
add_item('Open location', ?l, &method(:open_location))
|
|
505
533
|
add_item('Revert', &method(:revert))
|
|
506
534
|
add_separator
|
|
507
|
-
add_item('Save', &method(:save))
|
|
508
|
-
add_item('Save As', &method(:save_as))
|
|
535
|
+
add_item('Save', ?s, &method(:save))
|
|
536
|
+
add_item('Save As', ?S, &method(:save_as))
|
|
509
537
|
add_separator
|
|
510
|
-
add_item('Quit', &method(:quit))
|
|
538
|
+
add_item('Quit', ?q, &method(:quit))
|
|
511
539
|
title
|
|
512
540
|
end
|
|
513
541
|
end
|
|
@@ -516,17 +544,32 @@ module JSON
|
|
|
516
544
|
class EditMenu
|
|
517
545
|
include MenuExtension
|
|
518
546
|
|
|
547
|
+
# Copy data from model into primary clipboard.
|
|
548
|
+
def copy(item)
|
|
549
|
+
data = Editor.model2data(model.iter_first)
|
|
550
|
+
json = JSON.pretty_generate(data, :max_nesting => false)
|
|
551
|
+
c = Gtk::Clipboard.get(Gdk::Selection::PRIMARY)
|
|
552
|
+
c.text = json
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
# Copy json text from primary clipboard into model.
|
|
556
|
+
def paste(item)
|
|
557
|
+
c = Gtk::Clipboard.get(Gdk::Selection::PRIMARY)
|
|
558
|
+
if json = c.wait_for_text
|
|
559
|
+
window.ask_save if @changed
|
|
560
|
+
begin
|
|
561
|
+
window.edit json
|
|
562
|
+
rescue JSON::ParserError
|
|
563
|
+
window.clear
|
|
564
|
+
end
|
|
565
|
+
end
|
|
566
|
+
end
|
|
567
|
+
|
|
519
568
|
# Find a string in all nodes' contents and select the found node in the
|
|
520
569
|
# treeview.
|
|
521
570
|
def find(item)
|
|
522
|
-
search = ask_for_find_term or return
|
|
523
|
-
|
|
524
|
-
@search = Regexp.new(search)
|
|
525
|
-
rescue => e
|
|
526
|
-
Editor.error_dialog(self, "Evaluation of regex /#{search}/ failed: #{e}!")
|
|
527
|
-
return
|
|
528
|
-
end
|
|
529
|
-
iter = model.get_iter('0')
|
|
571
|
+
@search = ask_for_find_term(@search) or return
|
|
572
|
+
iter = model.get_iter('0') or return
|
|
530
573
|
iter.recursive_each do |i|
|
|
531
574
|
if @iter
|
|
532
575
|
if @iter != i
|
|
@@ -602,10 +645,13 @@ module JSON
|
|
|
602
645
|
def create
|
|
603
646
|
title = MenuItem.new('Edit')
|
|
604
647
|
title.submenu = menu
|
|
605
|
-
add_item('
|
|
606
|
-
add_item('
|
|
648
|
+
add_item('Copy', ?c, &method(:copy))
|
|
649
|
+
add_item('Paste', ?v, &method(:paste))
|
|
607
650
|
add_separator
|
|
608
|
-
add_item('
|
|
651
|
+
add_item('Find', ?f, &method(:find))
|
|
652
|
+
add_item('Find Again', ?g, &method(:find_again))
|
|
653
|
+
add_separator
|
|
654
|
+
add_item('Sort', ?S, &method(:sort))
|
|
609
655
|
title
|
|
610
656
|
end
|
|
611
657
|
end
|
|
@@ -636,8 +682,8 @@ module JSON
|
|
|
636
682
|
def create
|
|
637
683
|
title = MenuItem.new('Options')
|
|
638
684
|
title.submenu = menu
|
|
639
|
-
add_item('Collapsed nodes', CheckMenuItem, &method(:collapsed_nodes))
|
|
640
|
-
@pretty_item = add_item('Pretty saving', CheckMenuItem,
|
|
685
|
+
add_item('Collapsed nodes', nil, CheckMenuItem, &method(:collapsed_nodes))
|
|
686
|
+
@pretty_item = add_item('Pretty saving', nil, CheckMenuItem,
|
|
641
687
|
&method(:pretty_saving))
|
|
642
688
|
@pretty_item.active = true
|
|
643
689
|
window.unchange
|
|
@@ -723,7 +769,12 @@ module JSON
|
|
|
723
769
|
iter.type, iter.content = 'FalseClass', 'false'
|
|
724
770
|
end
|
|
725
771
|
when 'Numeric'
|
|
726
|
-
iter.content =
|
|
772
|
+
iter.content =
|
|
773
|
+
if value == 'Infinity'
|
|
774
|
+
value
|
|
775
|
+
else
|
|
776
|
+
(Integer(value) rescue Float(value) rescue 0).to_s
|
|
777
|
+
end
|
|
727
778
|
when 'String'
|
|
728
779
|
iter.content = value
|
|
729
780
|
when 'Hash', 'Array'
|
|
@@ -784,12 +835,13 @@ module JSON
|
|
|
784
835
|
[ Stock::OK, Dialog::RESPONSE_ACCEPT ],
|
|
785
836
|
[ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
|
|
786
837
|
)
|
|
838
|
+
dialog.width_request = 640
|
|
787
839
|
|
|
788
840
|
hbox = HBox.new(false, 5)
|
|
789
|
-
hbox.pack_start(Label.new("Key:"))
|
|
841
|
+
hbox.pack_start(Label.new("Key:"), false)
|
|
790
842
|
hbox.pack_start(key_input = Entry.new)
|
|
791
843
|
key_input.text = @key || ''
|
|
792
|
-
dialog.vbox.
|
|
844
|
+
dialog.vbox.pack_start(hbox, false)
|
|
793
845
|
key_input.signal_connect(:activate) do
|
|
794
846
|
if parent.any? { |c| c.content == key_input.text }
|
|
795
847
|
toplevel.display_status('Key already exists in Hash!')
|
|
@@ -800,11 +852,11 @@ module JSON
|
|
|
800
852
|
end
|
|
801
853
|
|
|
802
854
|
hbox = HBox.new(false, 5)
|
|
803
|
-
hbox.
|
|
855
|
+
hbox.pack_start(Label.new("Type:"), false)
|
|
804
856
|
hbox.pack_start(type_input = ComboBox.new(true))
|
|
805
857
|
ALL_TYPES.each { |t| type_input.append_text(t) }
|
|
806
858
|
type_input.active = @type || 0
|
|
807
|
-
dialog.vbox.
|
|
859
|
+
dialog.vbox.pack_start(hbox, false)
|
|
808
860
|
|
|
809
861
|
type_input.signal_connect(:changed) do
|
|
810
862
|
value_input.editable = false
|
|
@@ -824,12 +876,15 @@ module JSON
|
|
|
824
876
|
end
|
|
825
877
|
|
|
826
878
|
hbox = HBox.new(false, 5)
|
|
827
|
-
hbox.
|
|
879
|
+
hbox.pack_start(Label.new("Value:"), false)
|
|
828
880
|
hbox.pack_start(value_input = Entry.new)
|
|
881
|
+
value_input.width_chars = 60
|
|
829
882
|
value_input.text = @value || ''
|
|
830
|
-
dialog.vbox.
|
|
883
|
+
dialog.vbox.pack_start(hbox, false)
|
|
831
884
|
|
|
885
|
+
dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
|
|
832
886
|
dialog.show_all
|
|
887
|
+
self.focus = dialog
|
|
833
888
|
dialog.run do |response|
|
|
834
889
|
if response == Dialog::RESPONSE_ACCEPT
|
|
835
890
|
@key = key_input.text
|
|
@@ -854,7 +909,7 @@ module JSON
|
|
|
854
909
|
[ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
|
|
855
910
|
)
|
|
856
911
|
hbox = HBox.new(false, 5)
|
|
857
|
-
hbox.
|
|
912
|
+
hbox.pack_start(Label.new("Type:"), false)
|
|
858
913
|
hbox.pack_start(type_input = ComboBox.new(true))
|
|
859
914
|
default_active = 0
|
|
860
915
|
types = parent ? ALL_TYPES : CONTAINER_TYPES
|
|
@@ -865,26 +920,33 @@ module JSON
|
|
|
865
920
|
end
|
|
866
921
|
end
|
|
867
922
|
type_input.active = default_active
|
|
868
|
-
dialog.vbox.
|
|
923
|
+
dialog.vbox.pack_start(hbox, false)
|
|
869
924
|
type_input.signal_connect(:changed) do
|
|
870
925
|
configure_value(value_input, types[type_input.active])
|
|
871
926
|
end
|
|
872
927
|
|
|
873
928
|
hbox = HBox.new(false, 5)
|
|
874
|
-
hbox.
|
|
929
|
+
hbox.pack_start(Label.new("Value:"), false)
|
|
875
930
|
hbox.pack_start(value_input = Entry.new)
|
|
931
|
+
value_input.width_chars = 60
|
|
876
932
|
value_input.text = value_text if value_text
|
|
877
933
|
configure_value(value_input, types[type_input.active])
|
|
878
934
|
|
|
879
|
-
dialog.vbox.
|
|
935
|
+
dialog.vbox.pack_start(hbox, false)
|
|
880
936
|
|
|
937
|
+
dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
|
|
881
938
|
dialog.show_all
|
|
939
|
+
self.focus = dialog
|
|
882
940
|
dialog.run do |response|
|
|
883
941
|
if response == Dialog::RESPONSE_ACCEPT
|
|
884
942
|
type = types[type_input.active]
|
|
885
943
|
@content = case type
|
|
886
944
|
when 'Numeric'
|
|
887
|
-
|
|
945
|
+
if (t = value_input.text) == 'Infinity'
|
|
946
|
+
1 / 0.0
|
|
947
|
+
else
|
|
948
|
+
Integer(t) rescue Float(t) rescue 0
|
|
949
|
+
end
|
|
888
950
|
else
|
|
889
951
|
value_input.text
|
|
890
952
|
end.to_s
|
|
@@ -908,15 +970,18 @@ module JSON
|
|
|
908
970
|
)
|
|
909
971
|
hbox = HBox.new(false, 5)
|
|
910
972
|
|
|
911
|
-
hbox.
|
|
973
|
+
hbox.pack_start(Label.new("Order:"), false)
|
|
912
974
|
hbox.pack_start(order_input = Entry.new)
|
|
913
975
|
order_input.text = @order || 'x'
|
|
976
|
+
order_input.width_chars = 60
|
|
914
977
|
|
|
915
|
-
hbox.pack_start(reverse_checkbox = CheckButton.new('Reverse'))
|
|
978
|
+
hbox.pack_start(reverse_checkbox = CheckButton.new('Reverse'), false)
|
|
916
979
|
|
|
917
|
-
dialog.vbox.
|
|
980
|
+
dialog.vbox.pack_start(hbox, false)
|
|
918
981
|
|
|
982
|
+
dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
|
|
919
983
|
dialog.show_all
|
|
984
|
+
self.focus = dialog
|
|
920
985
|
dialog.run do |response|
|
|
921
986
|
if response == Dialog::RESPONSE_ACCEPT
|
|
922
987
|
return @order = order_input.text, reverse_checkbox.active?
|
|
@@ -929,7 +994,7 @@ module JSON
|
|
|
929
994
|
|
|
930
995
|
# Ask for a find term to search for in the tree. Returns the term as a
|
|
931
996
|
# string.
|
|
932
|
-
def ask_for_find_term
|
|
997
|
+
def ask_for_find_term(search = nil)
|
|
933
998
|
dialog = Dialog.new(
|
|
934
999
|
"Find a node matching regex in tree.",
|
|
935
1000
|
nil, nil,
|
|
@@ -938,16 +1003,28 @@ module JSON
|
|
|
938
1003
|
)
|
|
939
1004
|
hbox = HBox.new(false, 5)
|
|
940
1005
|
|
|
941
|
-
hbox.
|
|
1006
|
+
hbox.pack_start(Label.new("Regex:"), false)
|
|
942
1007
|
hbox.pack_start(regex_input = Entry.new)
|
|
943
|
-
|
|
1008
|
+
hbox.pack_start(icase_checkbox = CheckButton.new('Icase'), false)
|
|
1009
|
+
regex_input.width_chars = 60
|
|
1010
|
+
if search
|
|
1011
|
+
regex_input.text = search.source
|
|
1012
|
+
icase_checkbox.active = search.casefold?
|
|
1013
|
+
end
|
|
944
1014
|
|
|
945
|
-
dialog.vbox.
|
|
1015
|
+
dialog.vbox.pack_start(hbox, false)
|
|
946
1016
|
|
|
1017
|
+
dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
|
|
947
1018
|
dialog.show_all
|
|
1019
|
+
self.focus = dialog
|
|
948
1020
|
dialog.run do |response|
|
|
949
1021
|
if response == Dialog::RESPONSE_ACCEPT
|
|
950
|
-
|
|
1022
|
+
begin
|
|
1023
|
+
return Regexp.new(regex_input.text, icase_checkbox.active? ? Regexp::IGNORECASE : 0)
|
|
1024
|
+
rescue => e
|
|
1025
|
+
Editor.error_dialog(self, "Evaluation of regex /#{regex_input.text}/ failed: #{e}!")
|
|
1026
|
+
return
|
|
1027
|
+
end
|
|
951
1028
|
end
|
|
952
1029
|
end
|
|
953
1030
|
return
|
|
@@ -1004,6 +1081,18 @@ module JSON
|
|
|
1004
1081
|
data = read_data(@filename)
|
|
1005
1082
|
view_new_model Editor.data2model(data)
|
|
1006
1083
|
end
|
|
1084
|
+
|
|
1085
|
+
signal_connect(:button_release_event) do |_,event|
|
|
1086
|
+
if event.button == 2
|
|
1087
|
+
c = Gtk::Clipboard.get(Gdk::Selection::PRIMARY)
|
|
1088
|
+
if url = c.wait_for_text
|
|
1089
|
+
location_open url
|
|
1090
|
+
end
|
|
1091
|
+
false
|
|
1092
|
+
else
|
|
1093
|
+
true
|
|
1094
|
+
end
|
|
1095
|
+
end
|
|
1007
1096
|
end
|
|
1008
1097
|
|
|
1009
1098
|
# Creates the menu bar with the pulldown menus and returns it.
|
|
@@ -1063,9 +1152,11 @@ module JSON
|
|
|
1063
1152
|
# Quit this editor, that is, leave this editor's main loop.
|
|
1064
1153
|
def quit
|
|
1065
1154
|
ask_save if @changed
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1155
|
+
if Gtk.main_level > 0
|
|
1156
|
+
destroy
|
|
1157
|
+
Gtk.main_quit
|
|
1158
|
+
end
|
|
1159
|
+
nil
|
|
1069
1160
|
end
|
|
1070
1161
|
|
|
1071
1162
|
# Display the new title according to the editor's current state.
|
|
@@ -1083,6 +1174,22 @@ module JSON
|
|
|
1083
1174
|
self.view_new_model nil
|
|
1084
1175
|
end
|
|
1085
1176
|
|
|
1177
|
+
def check_pretty_printed(json)
|
|
1178
|
+
pretty = !!((nl_index = json.index("\n")) && nl_index != json.size - 1)
|
|
1179
|
+
@options_menu.pretty_item.active = pretty
|
|
1180
|
+
end
|
|
1181
|
+
private :check_pretty_printed
|
|
1182
|
+
|
|
1183
|
+
# Open the data at the location _uri_, if given. Otherwise open a dialog
|
|
1184
|
+
# to ask for the _uri_.
|
|
1185
|
+
def location_open(uri = nil)
|
|
1186
|
+
uri = ask_for_location unless uri
|
|
1187
|
+
uri or return
|
|
1188
|
+
ask_save if @changed
|
|
1189
|
+
data = load_location(uri) or return
|
|
1190
|
+
view_new_model Editor.data2model(data)
|
|
1191
|
+
end
|
|
1192
|
+
|
|
1086
1193
|
# Open the file _filename_ or call the #select_file method to ask for a
|
|
1087
1194
|
# filename.
|
|
1088
1195
|
def file_open(filename = nil)
|
|
@@ -1091,6 +1198,15 @@ module JSON
|
|
|
1091
1198
|
view_new_model Editor.data2model(data)
|
|
1092
1199
|
end
|
|
1093
1200
|
|
|
1201
|
+
# Edit the string _json_ in the editor.
|
|
1202
|
+
def edit(json)
|
|
1203
|
+
if json.respond_to? :read
|
|
1204
|
+
json = json.read
|
|
1205
|
+
end
|
|
1206
|
+
data = parse_json json
|
|
1207
|
+
view_new_model Editor.data2model(data)
|
|
1208
|
+
end
|
|
1209
|
+
|
|
1094
1210
|
# Save the current file.
|
|
1095
1211
|
def file_save
|
|
1096
1212
|
if @filename
|
|
@@ -1111,10 +1227,11 @@ module JSON
|
|
|
1111
1227
|
if path
|
|
1112
1228
|
data = Editor.model2data(@treeview.model.iter_first)
|
|
1113
1229
|
File.open(path + '.tmp', 'wb') do |output|
|
|
1230
|
+
data or break
|
|
1114
1231
|
if @options_menu.pretty_item.active?
|
|
1115
|
-
output.puts JSON.pretty_generate(data)
|
|
1232
|
+
output.puts JSON.pretty_generate(data, :max_nesting => false)
|
|
1116
1233
|
else
|
|
1117
|
-
output.write JSON.
|
|
1234
|
+
output.write JSON.generate(data, :max_nesting => false)
|
|
1118
1235
|
end
|
|
1119
1236
|
end
|
|
1120
1237
|
File.rename path + '.tmp', path
|
|
@@ -1131,49 +1248,62 @@ module JSON
|
|
|
1131
1248
|
if filename
|
|
1132
1249
|
if File.directory?(filename)
|
|
1133
1250
|
Editor.error_dialog(self, "Try to select a JSON file!")
|
|
1134
|
-
|
|
1251
|
+
nil
|
|
1135
1252
|
else
|
|
1136
|
-
data = read_data(filename)
|
|
1137
1253
|
@filename = filename
|
|
1138
|
-
|
|
1254
|
+
if data = read_data(filename)
|
|
1255
|
+
toplevel.display_status("Loaded data from '#@filename'.")
|
|
1256
|
+
end
|
|
1139
1257
|
display_title
|
|
1140
|
-
|
|
1258
|
+
data
|
|
1141
1259
|
end
|
|
1142
1260
|
end
|
|
1143
1261
|
end
|
|
1144
1262
|
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1263
|
+
# Load the data at location _uri_ into the editor as a JSON document.
|
|
1264
|
+
def load_location(uri)
|
|
1265
|
+
data = read_data(uri) or return
|
|
1266
|
+
@filename = nil
|
|
1267
|
+
toplevel.display_status("Loaded data from '#{uri}'.")
|
|
1268
|
+
display_title
|
|
1269
|
+
data
|
|
1148
1270
|
end
|
|
1149
|
-
private :check_pretty_printed
|
|
1150
1271
|
|
|
1151
|
-
|
|
1152
|
-
# ruby data structure, and return the data.
|
|
1153
|
-
def read_data(filename)
|
|
1154
|
-
json = File.read(filename)
|
|
1272
|
+
def parse_json(json)
|
|
1155
1273
|
check_pretty_printed(json)
|
|
1156
1274
|
if @encoding && !/^utf8$/i.match(@encoding)
|
|
1157
1275
|
iconverter = Iconv.new('utf8', @encoding)
|
|
1158
1276
|
json = iconverter.iconv(json)
|
|
1159
1277
|
end
|
|
1160
|
-
JSON::parse(json)
|
|
1161
|
-
|
|
1278
|
+
JSON::parse(json, :max_nesting => false, :create_additions => false)
|
|
1279
|
+
end
|
|
1280
|
+
private :parse_json
|
|
1281
|
+
|
|
1282
|
+
# Read a JSON document from the file named _filename_, parse it into a
|
|
1283
|
+
# ruby data structure, and return the data.
|
|
1284
|
+
def read_data(filename)
|
|
1285
|
+
open(filename) do |f|
|
|
1286
|
+
json = f.read
|
|
1287
|
+
return parse_json(json)
|
|
1288
|
+
end
|
|
1289
|
+
rescue => e
|
|
1162
1290
|
Editor.error_dialog(self, "Failed to parse JSON file: #{e}!")
|
|
1163
1291
|
return
|
|
1164
|
-
rescue SystemCallError => e
|
|
1165
|
-
quit
|
|
1166
1292
|
end
|
|
1167
1293
|
|
|
1168
1294
|
# Open a file selecton dialog, displaying _message_, and return the
|
|
1169
1295
|
# selected filename or nil, if no file was selected.
|
|
1170
1296
|
def select_file(message)
|
|
1171
1297
|
filename = nil
|
|
1172
|
-
fs = FileSelection.new(message)
|
|
1173
|
-
|
|
1298
|
+
fs = FileSelection.new(message)
|
|
1299
|
+
fs.set_modal(true)
|
|
1300
|
+
@default_dir = File.join(Dir.pwd, '') unless @default_dir
|
|
1301
|
+
fs.set_filename(@default_dir)
|
|
1302
|
+
fs.set_transient_for(self)
|
|
1174
1303
|
fs.signal_connect(:destroy) { Gtk.main_quit }
|
|
1175
1304
|
fs.ok_button.signal_connect(:clicked) do
|
|
1176
1305
|
filename = fs.filename
|
|
1306
|
+
@default_dir = File.join(File.dirname(filename), '')
|
|
1177
1307
|
fs.destroy
|
|
1178
1308
|
Gtk.main_quit
|
|
1179
1309
|
end
|
|
@@ -1185,13 +1315,41 @@ module JSON
|
|
|
1185
1315
|
Gtk.main
|
|
1186
1316
|
filename
|
|
1187
1317
|
end
|
|
1318
|
+
|
|
1319
|
+
# Ask for location URI a to load data from. Returns the URI as a string.
|
|
1320
|
+
def ask_for_location
|
|
1321
|
+
dialog = Dialog.new(
|
|
1322
|
+
"Load data from location...",
|
|
1323
|
+
nil, nil,
|
|
1324
|
+
[ Stock::OK, Dialog::RESPONSE_ACCEPT ],
|
|
1325
|
+
[ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
|
|
1326
|
+
)
|
|
1327
|
+
hbox = HBox.new(false, 5)
|
|
1328
|
+
|
|
1329
|
+
hbox.pack_start(Label.new("Location:"), false)
|
|
1330
|
+
hbox.pack_start(location_input = Entry.new)
|
|
1331
|
+
location_input.width_chars = 60
|
|
1332
|
+
location_input.text = @location || ''
|
|
1333
|
+
|
|
1334
|
+
dialog.vbox.pack_start(hbox, false)
|
|
1335
|
+
|
|
1336
|
+
dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
|
|
1337
|
+
dialog.show_all
|
|
1338
|
+
dialog.run do |response|
|
|
1339
|
+
if response == Dialog::RESPONSE_ACCEPT
|
|
1340
|
+
return @location = location_input.text
|
|
1341
|
+
end
|
|
1342
|
+
end
|
|
1343
|
+
return
|
|
1344
|
+
ensure
|
|
1345
|
+
dialog.destroy if dialog
|
|
1346
|
+
end
|
|
1188
1347
|
end
|
|
1189
1348
|
|
|
1190
1349
|
class << self
|
|
1191
1350
|
# Starts a JSON Editor. If a block was given, it yields
|
|
1192
1351
|
# to the JSON::Editor::MainWindow instance.
|
|
1193
|
-
def start(encoding =
|
|
1194
|
-
encoding ||= 'utf8'
|
|
1352
|
+
def start(encoding = 'utf8') # :yield: window
|
|
1195
1353
|
Gtk.init
|
|
1196
1354
|
@window = Editor::MainWindow.new(encoding)
|
|
1197
1355
|
@window.icon_list = [ Editor.fetch_icon('json') ]
|
|
@@ -1200,8 +1358,14 @@ module JSON
|
|
|
1200
1358
|
Gtk.main
|
|
1201
1359
|
end
|
|
1202
1360
|
|
|
1361
|
+
# Edit the string _json_ with encoding _encoding_ in the editor.
|
|
1362
|
+
def edit(json, encoding = 'utf8')
|
|
1363
|
+
start(encoding) do |window|
|
|
1364
|
+
window.edit json
|
|
1365
|
+
end
|
|
1366
|
+
end
|
|
1367
|
+
|
|
1203
1368
|
attr_reader :window
|
|
1204
1369
|
end
|
|
1205
1370
|
end
|
|
1206
1371
|
end
|
|
1207
|
-
# vim: set et sw=2 ts=2:
|