facets 1.2.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ProjectInfo +32 -25
- data/data/facets/index.yml +30 -6
- data/data/facets/units/binary/base.yaml +12 -0
- data/data/facets/units/binary/extra.yaml +8 -0
- data/data/facets/units/cex.yaml +7 -0
- data/data/facets/units/currency/base.yaml +268 -0
- data/data/facets/units/default.yaml +22 -0
- data/data/facets/units/dump_yaml.rb +309 -0
- data/data/facets/units/si/base.yaml +36 -0
- data/data/facets/units/si/derived.yaml +133 -0
- data/data/facets/units/si/extra.yaml +107 -0
- data/data/facets/units/standard.yaml +5 -0
- data/data/facets/units/uk.yaml +16 -0
- data/data/facets/units/uk/base.yaml +107 -0
- data/data/facets/units/us.yaml +16 -0
- data/data/facets/units/us/base.yaml +112 -0
- data/data/facets/units/xmethods/cached.yaml +83 -0
- data/data/facets/units/xmethods/mapping.yaml +85 -0
- data/lib/facet/array/join_sentence.rb +1 -0
- data/lib/facet/class/cattr.rb +1 -0
- data/lib/facet/class/cattr_accessor.rb +1 -0
- data/lib/facet/class/cattr_reader.rb +1 -0
- data/lib/facet/class/cattr_writer.rb +1 -0
- data/lib/facet/elementor.rb +1 -0
- data/lib/facet/enumerable/accumulate.rb +1 -0
- data/lib/facet/enumerable/collect_if.rb +1 -0
- data/lib/facet/enumerable/map_if.rb +1 -0
- data/lib/facet/file/self/append.rb +1 -0
- data/lib/facet/file/self/read_binary.rb +1 -0
- data/lib/facet/file/self/write.rb +1 -0
- data/lib/facet/json.rb +1 -0
- data/lib/facet/kernel/__self__.rb +1 -0
- data/lib/facet/kernel/methodname.rb +1 -0
- data/lib/facet/module/attr_query.rb +1 -0
- data/lib/facet/module/attr_validator.rb +1 -0
- data/lib/facet/module/inherit.rb +1 -0
- data/lib/facet/module/let.rb +1 -0
- data/lib/facet/module/mattr.rb +1 -0
- data/lib/facet/module/mattr_accessor.rb +1 -0
- data/lib/facet/module/mattr_reader.rb +1 -0
- data/lib/facet/module/mattr_writer.rb +1 -0
- data/lib/facet/module/singleton_to_module.rb +1 -0
- data/lib/facet/nilclass/op_cmp.rb +1 -0
- data/lib/facet/nilclass/succ.rb +1 -0
- data/lib/facet/recorder.rb +1 -0
- data/lib/facet/xoxo.rb +1 -0
- data/lib/facets/core/array.rb +1 -0
- data/lib/facets/core/array/join_sentence.rb +12 -0
- data/lib/facets/core/class.rb +4 -0
- data/lib/facets/core/{module → class}/cattr.rb +7 -9
- data/lib/facets/core/class/cattr_accessor.rb +2 -0
- data/lib/facets/core/class/cattr_reader.rb +3 -0
- data/lib/facets/core/class/cattr_writer.rb +2 -0
- data/lib/facets/core/dir/self/ls_r.rb +4 -9
- data/lib/facets/core/enumerable.rb +3 -0
- data/lib/facets/core/enumerable/accumulate.rb +25 -0
- data/lib/facets/core/enumerable/collect_if.rb +15 -0
- data/lib/facets/core/enumerable/ew.rb +1 -5
- data/lib/facets/core/enumerable/map_if.rb +3 -0
- data/lib/facets/core/file.rb +3 -0
- data/lib/facets/core/file/self/append.rb +8 -0
- data/lib/facets/core/file/self/create.rb +14 -8
- data/lib/facets/core/file/self/open_as_string.rb +31 -13
- data/lib/facets/core/file/self/read_binary.rb +8 -0
- data/lib/facets/core/file/self/read_list.rb +11 -7
- data/lib/facets/core/file/self/write.rb +8 -0
- data/lib/facets/core/fileutils/wc.rb +4 -9
- data/lib/facets/core/fileutils/which.rb +4 -9
- data/lib/facets/core/kernel.rb +2 -1
- data/lib/facets/core/kernel/__self__.rb +32 -0
- data/lib/facets/core/kernel/as.rb +1 -1
- data/lib/facets/core/kernel/assign_from.rb +3 -3
- data/lib/facets/core/kernel/assign_with.rb +2 -0
- data/lib/facets/core/kernel/me.rb +3 -2
- data/lib/facets/core/kernel/method_name.rb +2 -49
- data/lib/facets/core/kernel/methodname.rb +49 -0
- data/lib/facets/core/module.rb +9 -4
- data/lib/facets/core/module/attr_query.rb +56 -0
- data/lib/facets/core/module/attr_validator.rb +18 -0
- data/lib/facets/core/module/inherit.rb +70 -0
- data/lib/facets/core/module/integrate.rb +1 -1
- data/lib/facets/core/module/let.rb +55 -0
- data/lib/facets/core/module/mattr.rb +180 -0
- data/lib/facets/core/module/{cattr_accessor.rb → mattr_accessor.rb} +0 -0
- data/lib/facets/core/module/{cattr_reader.rb → mattr_reader.rb} +0 -0
- data/lib/facets/core/module/{cattr_writer.rb → mattr_writer.rb} +0 -0
- data/lib/facets/core/module/on_included.rb +3 -1
- data/lib/facets/core/module/singleton_to_module.rb +23 -0
- data/lib/facets/core/nilclass.rb +2 -0
- data/lib/facets/core/string/methodize.rb +4 -3
- data/lib/facets/core/string/modulize.rb +3 -3
- data/lib/facets/more/ansicode.rb +1 -1
- data/lib/facets/more/aspects.rb +1 -1
- data/lib/facets/more/basicobject.rb +67 -22
- data/lib/facets/more/classinherit.rb +2 -2
- data/lib/facets/more/cloneable.rb +1 -1
- data/lib/facets/more/consoleapp.rb +31 -20
- data/lib/facets/more/dictionary.rb +1 -1
- data/lib/facets/more/filelist.rb +2 -10
- data/lib/facets/more/functor.rb +6 -6
- data/lib/facets/more/json.rb +891 -0
- data/lib/facets/more/methodprobe.rb +1 -1
- data/lib/facets/more/multiton.rb +16 -8
- data/lib/facets/more/nilcomparable.rb +31 -49
- data/lib/facets/more/openobject.rb +50 -10
- data/lib/facets/more/recorder.rb +125 -0
- data/lib/facets/more/rtals.rb +199 -4
- data/lib/facets/more/typecast.rb +12 -12
- data/lib/facets/more/units.rb +20 -14
- data/lib/facets/more/xoxo.rb +519 -0
- data/setup.rb +283 -271
- data/test/lib/facets/core/array/test_at_rand.rb +1 -1
- data/test/lib/facets/core/array/test_delete_unless.rb +1 -1
- data/test/lib/facets/core/array/test_delete_values.rb +1 -1
- data/test/lib/facets/core/array/test_delete_values_at.rb +1 -1
- data/test/lib/facets/core/array/test_first.rb +1 -1
- data/test/lib/facets/core/array/test_head.rb +1 -1
- data/test/lib/facets/core/array/test_last_index.rb +1 -1
- data/test/lib/facets/core/array/test_merge.rb +1 -1
- data/test/lib/facets/core/array/test_mid.rb +1 -1
- data/test/lib/facets/core/array/test_middle.rb +1 -1
- data/test/lib/facets/core/array/test_op_fetch.rb +1 -1
- data/test/lib/facets/core/array/test_op_store.rb +1 -1
- data/test/lib/facets/core/array/test_pick.rb +1 -1
- data/test/lib/facets/core/array/test_pos.rb +1 -1
- data/test/lib/facets/core/array/test_pull.rb +1 -1
- data/test/lib/facets/core/array/test_rand_index.rb +1 -1
- data/test/lib/facets/core/array/test_rand_subset.rb +1 -1
- data/test/lib/facets/core/array/test_range.rb +1 -1
- data/test/lib/facets/core/array/test_rotate.rb +1 -1
- data/test/lib/facets/core/array/test_select.rb +1 -1
- data/test/lib/facets/core/array/test_shuffle.rb +1 -1
- data/test/lib/facets/core/array/test_slap.rb +1 -1
- data/test/lib/facets/core/array/test_thru.rb +1 -1
- data/test/lib/facets/core/array/test_to_b.rb +1 -1
- data/test/lib/facets/core/array/test_to_h.rb +1 -1
- data/test/lib/facets/core/array/test_to_hash.rb +1 -1
- data/test/lib/facets/core/binding/self/test_of_caller.rb +1 -1
- data/test/lib/facets/core/binding/test___LINE__.rb +1 -1
- data/test/lib/facets/core/binding/test_call_stack.rb +1 -1
- data/test/lib/facets/core/binding/test_called.rb +1 -1
- data/test/lib/facets/core/binding/test_caller.rb +1 -1
- data/test/lib/facets/core/binding/test_defined.rb +1 -1
- data/test/lib/facets/core/binding/test_eval.rb +1 -1
- data/test/lib/facets/core/binding/test_local_variables.rb +1 -1
- data/test/lib/facets/core/binding/test_method_name.rb +1 -1
- data/test/lib/facets/core/binding/test_op_fetch.rb +1 -1
- data/test/lib/facets/core/binding/test_op_store.rb +1 -1
- data/test/lib/facets/core/binding/test_self.rb +1 -1
- data/test/lib/facets/core/{module/test_cattr_accessor.rb → class/test_cattr.rb} +11 -3
- data/test/lib/facets/core/class/test_descendents.rb +1 -1
- data/test/lib/facets/core/class/test_method_name.rb +1 -1
- data/test/lib/facets/core/class/test_remove_descendents.rb +1 -1
- data/test/lib/facets/core/class/test_unix_path.rb +1 -1
- data/test/lib/facets/core/comparable/test_at_least.rb +1 -1
- data/test/lib/facets/core/comparable/test_clip.rb +1 -1
- data/test/lib/facets/core/comparable/test_cmp.rb +1 -1
- data/test/lib/facets/core/continuation/self/test_create.rb +1 -1
- data/test/lib/facets/core/date/test_days_in_month.rb +1 -1
- data/test/lib/facets/core/date/test_days_of_month.rb +1 -1
- data/test/lib/facets/core/date/test_stamp.rb +1 -1
- data/test/lib/facets/core/date/test_to_date.rb +1 -1
- data/test/lib/facets/core/date/test_to_s.rb +1 -1
- data/test/lib/facets/core/date/test_to_time.rb +1 -1
- data/test/lib/facets/core/dir/self/test_ancestor.rb +1 -1
- data/test/lib/facets/core/dir/self/test_ascend.rb +1 -1
- data/test/lib/facets/core/enumerable/self/test_combinations.rb +1 -1
- data/test/lib/facets/core/enumerable/self/test_cross.rb +1 -1
- data/test/lib/facets/core/enumerable/test_collect_with_index.rb +1 -1
- data/test/lib/facets/core/enumerable/test_commonality.rb +1 -1
- data/test/lib/facets/core/enumerable/test_compact_collect.rb +1 -1
- data/test/lib/facets/core/enumerable/test_cross.rb +1 -1
- data/test/lib/facets/core/enumerable/test_each_combination.rb +1 -1
- data/test/lib/facets/core/enumerable/test_each_pair.rb +1 -1
- data/test/lib/facets/core/enumerable/test_each_slice.rb +1 -1
- data/test/lib/facets/core/enumerable/test_each_unique_pair.rb +1 -1
- data/test/lib/facets/core/enumerable/test_entropy.rb +1 -1
- data/test/lib/facets/core/enumerable/test_every.rb +1 -1
- data/test/lib/facets/core/enumerable/test_ew.rb +1 -1
- data/test/lib/facets/core/enumerable/test_filter_collect.rb +1 -1
- data/test/lib/facets/core/enumerable/test_find_collisions.rb +1 -1
- data/test/lib/facets/core/enumerable/test_frequency.rb +1 -1
- data/test/lib/facets/core/enumerable/test_graph.rb +1 -1
- data/test/lib/facets/core/enumerable/test_ideal_entropy.rb +1 -1
- data/test/lib/facets/core/enumerable/test_none.rb +1 -1
- data/test/lib/facets/core/enumerable/test_occur.rb +1 -1
- data/test/lib/facets/core/enumerable/test_one.rb +1 -1
- data/test/lib/facets/core/enumerable/test_op_pow.rb +1 -1
- data/test/lib/facets/core/enumerable/test_partition_by.rb +1 -1
- data/test/lib/facets/core/enumerable/test_permute.rb +1 -1
- data/test/lib/facets/core/enumerable/test_probability.rb +1 -1
- data/test/lib/facets/core/enumerable/test_to_h.rb +1 -1
- data/test/lib/facets/core/enumerable/test_uniq_by.rb +1 -1
- data/test/lib/facets/core/file/self/test_create.rb +14 -9
- data/test/lib/facets/core/file/self/test_open_as_string.rb +21 -11
- data/test/lib/facets/core/file/self/test_read_list.rb +11 -8
- data/test/lib/facets/core/file/self/test_sanitize.rb +1 -1
- data/test/lib/facets/core/file/self/test_split_all.rb +1 -1
- data/test/lib/facets/core/float/test_round_at.rb +1 -1
- data/test/lib/facets/core/float/test_round_to.rb +1 -1
- data/test/lib/facets/core/hash/self/test_zipnew.rb +1 -1
- data/test/lib/facets/core/hash/test_alias.rb +1 -1
- data/test/lib/facets/core/hash/test_assert_has_keys.rb +1 -1
- data/test/lib/facets/core/hash/test_assert_has_only_keys.rb +1 -1
- data/test/lib/facets/core/hash/test_at.rb +1 -1
- data/test/lib/facets/core/hash/test_collate.rb +1 -1
- data/test/lib/facets/core/hash/test_each.rb +1 -1
- data/test/lib/facets/core/hash/test_each_with_index.rb +1 -1
- data/test/lib/facets/core/hash/test_each_with_key.rb +1 -1
- data/test/lib/facets/core/hash/test_graph.rb +1 -1
- data/test/lib/facets/core/hash/test_has_keys.rb +1 -1
- data/test/lib/facets/core/hash/test_has_only_keys.rb +1 -1
- data/test/lib/facets/core/hash/test_inverse.rb +1 -1
- data/test/lib/facets/core/hash/test_keys_to_s.rb +1 -1
- data/test/lib/facets/core/hash/test_keys_to_sym.rb +1 -1
- data/test/lib/facets/core/hash/test_op_fetch.rb +1 -1
- data/test/lib/facets/core/hash/test_op_lshift.rb +1 -1
- data/test/lib/facets/core/hash/test_rand_key.rb +1 -1
- data/test/lib/facets/core/hash/test_rand_pair.rb +1 -1
- data/test/lib/facets/core/hash/test_rand_value.rb +1 -1
- data/test/lib/facets/core/hash/test_replace_each.rb +1 -1
- data/test/lib/facets/core/hash/test_shuffle.rb +1 -1
- data/test/lib/facets/core/hash/test_slice.rb +1 -1
- data/test/lib/facets/core/hash/test_swap.rb +1 -1
- data/test/lib/facets/core/hash/test_swapkey.rb +1 -1
- data/test/lib/facets/core/hash/test_to_h.rb +1 -1
- data/test/lib/facets/core/hash/test_to_ostruct.rb +1 -1
- data/test/lib/facets/core/hash/test_to_ostruct_recurse.rb +1 -1
- data/test/lib/facets/core/hash/test_traverse.rb +1 -1
- data/test/lib/facets/core/hash/test_update_each.rb +1 -1
- data/test/lib/facets/core/hash/test_update_keys.rb +1 -1
- data/test/lib/facets/core/hash/test_update_values.rb +1 -1
- data/test/lib/facets/core/hash/test_weave.rb +1 -1
- data/test/lib/facets/core/integer/test_factorial.rb +1 -1
- data/test/lib/facets/core/integer/test_multiple.rb +1 -1
- data/test/lib/facets/core/integer/test_ordinal.rb +1 -1
- data/test/lib/facets/core/integer/test_times_collect.rb +1 -1
- data/test/lib/facets/core/kernel/test___class__.rb +1 -1
- data/test/lib/facets/core/kernel/test_as.rb +1 -1
- data/test/lib/facets/core/kernel/test_assign_from.rb +1 -1
- data/test/lib/facets/core/kernel/test_assign_with.rb +1 -1
- data/test/lib/facets/core/kernel/test_bool.rb +1 -1
- data/test/lib/facets/core/kernel/test_bug.rb +1 -1
- data/test/lib/facets/core/kernel/test_call_stack.rb +1 -1
- data/test/lib/facets/core/kernel/test_called.rb +1 -1
- data/test/lib/facets/core/kernel/test_constant.rb +1 -1
- data/test/lib/facets/core/kernel/test_copy.rb +1 -1
- data/test/lib/facets/core/kernel/test_deep_copy.rb +1 -1
- data/test/lib/facets/core/kernel/test_demo.rb +1 -1
- data/test/lib/facets/core/kernel/test_fn.rb +1 -1
- data/test/lib/facets/core/kernel/test_generate_method_name.rb +1 -1
- data/test/lib/facets/core/kernel/test_get_by_id.rb +1 -1
- data/test/lib/facets/core/kernel/test_here.rb +1 -1
- data/test/lib/facets/core/kernel/test_in.rb +1 -1
- data/test/lib/facets/core/kernel/test_maybe.rb +1 -1
- data/test/lib/facets/core/kernel/test_metaclass.rb +1 -1
- data/test/lib/facets/core/kernel/test_method.rb +1 -1
- data/test/lib/facets/core/kernel/{test_method_name.rb → test_methodname.rb} +3 -3
- data/test/lib/facets/core/kernel/test_methods.rb +1 -1
- data/test/lib/facets/core/kernel/test_new.rb +1 -1
- data/test/lib/facets/core/kernel/test_object_class.rb +1 -1
- data/test/lib/facets/core/kernel/test_object_hexid.rb +1 -1
- data/test/lib/facets/core/kernel/test_require_all.rb +1 -1
- data/test/lib/facets/core/kernel/test_require_esc.rb +1 -1
- data/test/lib/facets/core/kernel/test_require_facet.rb +1 -1
- data/test/lib/facets/core/kernel/test_resc.rb +1 -1
- data/test/lib/facets/core/kernel/test_returning.rb +1 -1
- data/test/lib/facets/core/kernel/test_send_as.rb +1 -1
- data/test/lib/facets/core/kernel/test_set_from.rb +1 -1
- data/test/lib/facets/core/kernel/test_set_with.rb +1 -1
- data/test/lib/facets/core/kernel/test_silently.rb +1 -1
- data/test/lib/facets/core/kernel/test_singleton.rb +1 -1
- data/test/lib/facets/core/kernel/test_superior.rb +1 -1
- data/test/lib/facets/core/kernel/test_supermethod.rb +1 -1
- data/test/lib/facets/core/kernel/test_this.rb +1 -1
- data/test/lib/facets/core/kernel/test_to_b.rb +1 -1
- data/test/lib/facets/core/kernel/test_to_bool.rb +1 -1
- data/test/lib/facets/core/kernel/test_uri.rb +1 -1
- data/test/lib/facets/core/kernel/test_val.rb +1 -1
- data/test/lib/facets/core/kernel/test_with_accessor.rb +1 -1
- data/test/lib/facets/core/matchdata/test_match.rb +1 -1
- data/test/lib/facets/core/matchdata/test_matchtree.rb +1 -1
- data/test/lib/facets/core/module/test_abstract.rb +1 -1
- data/test/lib/facets/core/module/test_alias_module_function.rb +1 -1
- data/test/lib/facets/core/module/test_ancestor.rb +1 -1
- data/test/lib/facets/core/module/test_basename.rb +1 -1
- data/test/lib/facets/core/module/test_by_name.rb +1 -1
- data/test/lib/facets/core/module/test_clone_using.rb +1 -1
- data/test/lib/facets/core/module/test_dirname.rb +1 -1
- data/test/lib/facets/core/module/test_equate_on.rb +1 -1
- data/test/lib/facets/core/module/test_generate_instance_method_name.rb +1 -1
- data/test/lib/facets/core/module/test_include_as.rb +1 -1
- data/test/lib/facets/core/module/test_inherit.rb +58 -0
- data/test/lib/facets/core/module/test_initializer.rb +1 -1
- data/test/lib/facets/core/module/test_instance_methods.rb +1 -1
- data/test/lib/facets/core/module/test_integrate.rb +1 -1
- data/test/lib/facets/core/module/test_let.rb +31 -0
- data/test/lib/facets/core/module/test_mattr.rb +71 -0
- data/test/lib/facets/core/module/test_memoize.rb +1 -1
- data/test/lib/facets/core/module/test_modspace.rb +1 -1
- data/test/lib/facets/core/module/test_namespace.rb +1 -1
- data/test/lib/facets/core/module/test_nesting.rb +1 -1
- data/test/lib/facets/core/module/test_on_included.rb +36 -0
- data/test/lib/facets/core/module/test_redef.rb +1 -1
- data/test/lib/facets/core/module/test_redefine_method.rb +1 -1
- data/test/lib/facets/core/module/test_redirect.rb +1 -1
- data/test/lib/facets/core/module/test_redirect_method.rb +1 -1
- data/test/lib/facets/core/module/test_remove.rb +1 -1
- data/test/lib/facets/core/module/test_rename.rb +1 -1
- data/test/lib/facets/core/module/test_rename_method.rb +1 -1
- data/test/lib/facets/core/module/test_revisal.rb +1 -1
- data/test/lib/facets/core/module/test_shadow_method.rb +1 -1
- data/test/lib/facets/core/module/test_sort_on.rb +1 -1
- data/test/lib/facets/core/module/test_undef.rb +1 -1
- data/test/lib/facets/core/module/test_wrap.rb +1 -1
- data/test/lib/facets/core/module/test_wrap_method.rb +1 -1
- data/test/lib/facets/core/nilclass/{test_to_f.rb → test_blank.rb} +5 -5
- data/test/lib/facets/core/nilclass/test_empty.rb +1 -1
- data/test/lib/facets/core/nilclass/test_include.rb +1 -1
- data/test/lib/facets/core/nilclass/test_op_fetch.rb +1 -1
- data/test/lib/facets/core/nilclass/test_size.rb +1 -1
- data/test/lib/facets/core/nilclass/test_to_h.rb +1 -1
- data/test/lib/facets/core/{float → numeric}/test_approx.rb +4 -3
- data/test/lib/facets/core/numeric/test_ceil_multiple.rb +1 -1
- data/test/lib/facets/core/numeric/test_succ.rb +1 -1
- data/test/lib/facets/core/numeric/test_to_b.rb +1 -1
- data/test/lib/facets/core/ostruct/test___merge__.rb +1 -1
- data/test/lib/facets/core/ostruct/test___update__.rb +1 -1
- data/test/lib/facets/core/ostruct/test_op_fetch.rb +1 -1
- data/test/lib/facets/core/ostruct/test_op_store.rb +1 -1
- data/test/lib/facets/core/proc/test_compose.rb +1 -1
- data/test/lib/facets/core/proc/test_to_method.rb +1 -1
- data/test/lib/facets/core/range/test_to_r.rb +1 -1
- data/test/lib/facets/core/range/test_to_range.rb +1 -1
- data/test/lib/facets/core/range/test_umbrella.rb +1 -1
- data/test/lib/facets/core/range/test_within.rb +1 -1
- data/test/lib/facets/core/regexp/test_arity.rb +1 -1
- data/test/lib/facets/core/regexp/test_to_re.rb +1 -1
- data/test/lib/facets/core/regexp/test_to_regexp.rb +1 -1
- data/test/lib/facets/core/string/self/test_interpolate.rb +1 -1
- data/test/lib/facets/core/string/self/test_patterns.rb +1 -1
- data/test/lib/facets/core/string/self/test_rand_letter.rb +1 -1
- data/test/lib/facets/core/string/test_align_center.rb +1 -1
- data/test/lib/facets/core/string/test_at_rand.rb +1 -1
- data/test/lib/facets/core/string/test_basename.rb +1 -1
- data/test/lib/facets/core/string/test_blank.rb +1 -1
- data/test/lib/facets/core/string/test_bracket.rb +1 -1
- data/test/lib/facets/core/string/test_camelcase.rb +1 -1
- data/test/lib/facets/core/string/test_camelize.rb +1 -1
- data/test/lib/facets/core/string/test_capitalized.rb +1 -1
- data/test/lib/facets/core/string/test_chars.rb +1 -1
- data/test/lib/facets/core/string/test_cmp.rb +1 -1
- data/test/lib/facets/core/string/test_demodulize.rb +1 -1
- data/test/lib/facets/core/string/test_downcase.rb +1 -1
- data/test/lib/facets/core/string/test_dresner.rb +1 -1
- data/test/lib/facets/core/string/test_each_char.rb +1 -1
- data/test/lib/facets/core/string/test_each_word.rb +1 -1
- data/test/lib/facets/core/string/test_first.rb +1 -1
- data/test/lib/facets/core/string/test_fold.rb +1 -1
- data/test/lib/facets/core/string/test_frequency.rb +1 -1
- data/test/lib/facets/core/string/test_humanize.rb +1 -1
- data/test/lib/facets/core/string/test_indent.rb +1 -1
- data/test/lib/facets/core/string/test_index_all.rb +1 -1
- data/test/lib/facets/core/string/test_last.rb +1 -1
- data/test/lib/facets/core/string/test_line_wrap.rb +1 -1
- data/test/lib/facets/core/string/test_lines.rb +1 -1
- data/test/lib/facets/core/string/test_lowercase.rb +1 -1
- data/test/lib/facets/core/string/test_margin.rb +1 -1
- data/test/lib/facets/core/string/test_methodize.rb +1 -1
- data/test/lib/facets/core/string/test_modulize.rb +1 -1
- data/test/lib/facets/core/string/test_mscan.rb +1 -1
- data/test/lib/facets/core/string/test_natcmp.rb +1 -1
- data/test/lib/facets/core/string/test_nchar.rb +1 -1
- data/test/lib/facets/core/string/test_pathize.rb +1 -1
- data/test/lib/facets/core/string/test_pop.rb +1 -1
- data/test/lib/facets/core/string/test_probability.rb +1 -1
- data/test/lib/facets/core/string/test_push.rb +1 -1
- data/test/lib/facets/core/string/test_quote.rb +1 -1
- data/test/lib/facets/core/string/test_rand_byte.rb +1 -1
- data/test/lib/facets/core/string/test_rand_index.rb +1 -1
- data/test/lib/facets/core/string/test_range.rb +1 -1
- data/test/lib/facets/core/string/test_range_all.rb +1 -1
- data/test/lib/facets/core/string/test_range_of_line.rb +1 -1
- data/test/lib/facets/core/string/test_regesc.rb +1 -1
- data/test/lib/facets/core/string/test_shatter.rb +1 -1
- data/test/lib/facets/core/string/test_shift.rb +1 -1
- data/test/lib/facets/core/string/test_shuffle.rb +1 -1
- data/test/lib/facets/core/string/test_similarity.rb +1 -1
- data/test/lib/facets/core/string/test_singular.rb +1 -1
- data/test/lib/facets/core/string/test_slap.rb +1 -1
- data/test/lib/facets/core/string/test_soundex.rb +1 -1
- data/test/lib/facets/core/string/test_succ.rb +1 -1
- data/test/lib/facets/core/string/test_to_a.rb +1 -1
- data/test/lib/facets/core/string/test_to_arr.rb +1 -1
- data/test/lib/facets/core/string/test_to_b.rb +1 -1
- data/test/lib/facets/core/string/test_to_const.rb +1 -1
- data/test/lib/facets/core/string/test_to_date.rb +1 -1
- data/test/lib/facets/core/string/test_to_proc.rb +1 -1
- data/test/lib/facets/core/string/test_to_re.rb +1 -1
- data/test/lib/facets/core/string/test_to_time.rb +1 -1
- data/test/lib/facets/core/string/test_unix_crypt.rb +1 -1
- data/test/lib/facets/core/string/test_unpack.rb +1 -1
- data/test/lib/facets/core/string/test_unshift.rb +1 -1
- data/test/lib/facets/core/string/test_upcase.rb +1 -1
- data/test/lib/facets/core/string/test_whitespace.rb +1 -1
- data/test/lib/facets/core/string/test_word_filter.rb +1 -1
- data/test/lib/facets/core/string/test_word_wrap.rb +1 -1
- data/test/lib/facets/core/string/test_words.rb +1 -1
- data/test/lib/facets/core/symbol/test_camelcase.rb +1 -1
- data/test/lib/facets/core/symbol/test_camelize.rb +1 -1
- data/test/lib/facets/core/symbol/test_capitalize.rb +1 -1
- data/test/lib/facets/core/symbol/test_capitalized.rb +1 -1
- data/test/lib/facets/core/symbol/test_downcase.rb +1 -1
- data/test/lib/facets/core/symbol/test_not.rb +1 -1
- data/test/lib/facets/core/symbol/test_pad.rb +1 -1
- data/test/lib/facets/core/symbol/test_succ.rb +1 -1
- data/test/lib/facets/core/symbol/test_to_const.rb +1 -1
- data/test/lib/facets/core/symbol/test_to_proc.rb +1 -1
- data/test/lib/facets/core/symbol/test_to_str.rb +1 -1
- data/test/lib/facets/core/symbol/test_underscore.rb +1 -1
- data/test/lib/facets/core/symbol/test_upcase.rb +1 -1
- data/test/lib/facets/core/time/test_change.rb +1 -1
- data/test/lib/facets/core/time/test_elapse.rb +1 -1
- data/test/lib/facets/core/time/test_stamp.rb +1 -1
- data/test/lib/facets/core/time/test_to_date.rb +1 -1
- data/test/lib/facets/core/time/test_to_s.rb +1 -1
- data/test/lib/facets/core/time/test_to_time.rb +1 -1
- data/test/lib/facets/more/test_annotation.rb +1 -1
- data/test/lib/facets/more/test_ansicode.rb +1 -1
- data/test/lib/facets/more/test_association.rb +1 -1
- data/test/lib/facets/more/test_basicobject.rb +58 -0
- data/test/lib/facets/more/test_bbcode.rb +1 -1
- data/test/lib/facets/more/test_bitmask.rb +1 -1
- data/test/lib/facets/more/test_bytes.rb +1 -1
- data/test/lib/facets/more/test_classinherit.rb +1 -1
- data/test/lib/facets/more/test_classmethods.rb +1 -1
- data/test/lib/facets/more/test_coroutine.rb +1 -1
- data/test/lib/facets/more/test_crypt.rb +1 -1
- data/test/lib/facets/more/test_dictionary.rb +1 -1
- data/test/lib/facets/more/test_elementor.rb +48 -0
- data/test/lib/facets/more/test_enumerablepass.rb +1 -1
- data/test/lib/facets/more/test_floatstring.rb +1 -1
- data/test/lib/facets/more/test_functor.rb +1 -1
- data/test/lib/facets/more/test_inheritor.rb +1 -1
- data/test/lib/facets/more/test_interval.rb +1 -1
- data/test/lib/facets/more/test_json.rb +232 -0
- data/test/lib/facets/more/test_lisp.rb +1 -1
- data/test/lib/facets/more/test_lisp_format.rb +1 -1
- data/test/lib/facets/more/test_lrucache.rb +1 -1
- data/test/lib/facets/more/test_mathconstants.rb +1 -1
- data/test/lib/facets/more/test_methodprobe.rb +1 -1
- data/test/lib/facets/more/test_multipliers.rb +1 -1
- data/test/lib/facets/more/test_multiton.rb +1 -1
- data/test/lib/facets/more/test_nackclass.rb +1 -1
- data/test/lib/facets/more/test_nilcomparable.rb +6 -2
- data/test/lib/facets/more/test_openobject.rb +1 -1
- data/test/lib/facets/more/test_overload.rb +1 -1
- data/test/lib/facets/more/test_paramix.rb +1 -1
- data/test/lib/facets/more/test_preinitialize.rb +1 -1
- data/test/lib/facets/more/test_promoteself.rb +1 -1
- data/test/lib/facets/more/test_recorder.rb +44 -0
- data/test/lib/facets/more/test_snapshot.rb +1 -1
- data/test/lib/facets/more/test_statichash.rb +1 -1
- data/test/lib/facets/more/test_syncarray.rb +1 -1
- data/test/lib/facets/more/test_synchash.rb +1 -1
- data/test/lib/facets/more/test_tagiterator.rb +1 -1
- data/test/lib/facets/more/test_timer.rb +1 -1
- data/test/lib/facets/more/test_times.rb +1 -1
- data/test/lib/facets/more/test_tuple.rb +1 -1
- data/test/lib/facets/more/test_typecast.rb +2 -2
- data/test/lib/facets/more/test_uninheritable.rb +1 -1
- data/test/lib/facets/more/test_units.rb +16 -10
- data/test/lib/facets/more/test_xoxo.rb +288 -0
- data/test/lib/facets/more/test_yamlstruct.rb +1 -1
- metadata +92 -25
- data/lib/facet/kernel/instance.rb +0 -1
- data/lib/facet/module/cattr.rb +0 -1
- data/lib/facet/module/cattr_accessor.rb +0 -1
- data/lib/facet/module/cattr_reader.rb +0 -1
- data/lib/facet/module/cattr_writer.rb +0 -1
- data/lib/facets/core/kernel/instance.rb +0 -29
- data/test/FIXTURE/create_file +0 -1
- data/test/FIXTURE/open_as_string_file +0 -1
- data/test/FIXTURE/read_list_file +0 -6
- data/test/lib/facets/core/dir/self/test_ls_r.rb +0 -52
- data/test/lib/facets/core/fileutils/test_wc.rb +0 -68
- data/test/lib/facets/core/fileutils/test_which.rb +0 -61
- data/test/testdir.rb +0 -8
@@ -38,7 +38,7 @@
|
|
38
38
|
# the behavior of classes themselves when they are subclassed.
|
39
39
|
# To achieve the same behavior with modules requires some clever
|
40
40
|
# Ruby karate. ClassInherit provides a nice solution.
|
41
|
-
# Simply place the class inheritable methods in the block
|
41
|
+
# Simply place the class inheritable methods in the block
|
42
42
|
# parameter of the special module method ClassInherit.
|
43
43
|
#
|
44
44
|
# module Mix
|
@@ -64,7 +64,7 @@
|
|
64
64
|
# the given block is evaluated, then the ClassInherit module
|
65
65
|
# is extended against the current module.
|
66
66
|
#
|
67
|
-
# The above is actually equivalent to putting the class/module
|
67
|
+
# The above is actually equivalent to putting the class/module
|
68
68
|
# methods in a nested ClassInherit module and extending the
|
69
69
|
# module _manually_, eg.
|
70
70
|
#
|
@@ -25,22 +25,22 @@
|
|
25
25
|
|
26
26
|
module Console ; end
|
27
27
|
|
28
|
-
#:title: Console
|
28
|
+
#:title: Console Command
|
29
29
|
#
|
30
|
-
# Console::
|
30
|
+
# Console::Command provides a clean and easy way
|
31
31
|
# to create a command line interface for your program.
|
32
|
-
# The unique technique utlizes
|
32
|
+
# The unique technique utlizes a Commandline to Object
|
33
33
|
# Mapping (COM) to make it quick and easy.
|
34
34
|
#
|
35
35
|
# == Synopsis
|
36
36
|
#
|
37
|
-
#
|
37
|
+
# Let's make an executable called 'mycmd'.
|
38
38
|
#
|
39
39
|
# #!/usr/bin/env ruby
|
40
40
|
#
|
41
|
-
# require 'facet/
|
41
|
+
# require 'facet/console_command'
|
42
42
|
#
|
43
|
-
#
|
43
|
+
# MyCmd << Console::Command
|
44
44
|
#
|
45
45
|
# def _v
|
46
46
|
# $VERBOSE = true
|
@@ -56,27 +56,30 @@ module Console ; end
|
|
56
56
|
#
|
57
57
|
# end
|
58
58
|
#
|
59
|
-
#
|
59
|
+
# MyCmd.execute
|
60
60
|
#
|
61
61
|
# Then on the command line:
|
62
62
|
#
|
63
|
-
# >
|
63
|
+
# > mycmd jump
|
64
64
|
# Jump
|
65
65
|
#
|
66
|
-
# >
|
66
|
+
# > mycmd -v jump
|
67
67
|
# JUMP! JUMP! JUMP!
|
68
68
|
#
|
69
69
|
|
70
|
-
class Console::
|
70
|
+
class Console::Command
|
71
|
+
|
72
|
+
def execute( argv=nil )
|
71
73
|
|
72
|
-
|
74
|
+
argv ||= ARGV # argv remains unchanged
|
75
|
+
args = argv.dup # args is manipulated
|
73
76
|
|
74
|
-
|
77
|
+
# process options
|
75
78
|
|
76
|
-
|
77
|
-
|
78
|
-
if md = %r{^[-]}.match(
|
79
|
-
opt =
|
79
|
+
i = 0;
|
80
|
+
while i < argv.size
|
81
|
+
if md = %r{^[-]}.match( argv[i] )
|
82
|
+
opt = argv[i].gsub('-','_')
|
80
83
|
if self.respond_to?( opt )
|
81
84
|
m = method( opt )
|
82
85
|
c = m.arity
|
@@ -96,13 +99,12 @@ class Console::Application
|
|
96
99
|
i += 1
|
97
100
|
end
|
98
101
|
|
99
|
-
#
|
102
|
+
# no secondary commands
|
100
103
|
|
101
104
|
if self.respond_to?(:main)
|
102
105
|
main( *args )
|
103
|
-
#exit 0
|
104
106
|
|
105
|
-
# secondary
|
107
|
+
# secondary commands
|
106
108
|
|
107
109
|
elsif not args.empty?
|
108
110
|
if self.respond_to?( args.first )
|
@@ -116,9 +118,13 @@ class Console::Application
|
|
116
118
|
end
|
117
119
|
end
|
118
120
|
|
121
|
+
# default secondary command
|
122
|
+
|
119
123
|
elsif self.respond_to?( :default )
|
120
124
|
default(*args)
|
121
125
|
|
126
|
+
# error
|
127
|
+
|
122
128
|
else
|
123
129
|
if self.private_methods.include?( "no_action_error" )
|
124
130
|
no_action_error( *args )
|
@@ -129,6 +135,11 @@ class Console::Application
|
|
129
135
|
|
130
136
|
end
|
131
137
|
|
132
|
-
end
|
138
|
+
end
|
133
139
|
|
140
|
+
alias_method :go, :execute
|
141
|
+
|
134
142
|
end
|
143
|
+
|
144
|
+
# temporary backward compatability
|
145
|
+
Console::Application = Console::Command
|
data/lib/facets/more/filelist.rb
CHANGED
@@ -449,7 +449,7 @@ end # FileList
|
|
449
449
|
# |_|\___||___/\__|
|
450
450
|
#
|
451
451
|
|
452
|
-
# TODO
|
452
|
+
# TODO This test needs a mock File class.
|
453
453
|
|
454
454
|
# FileList can't be tested without a FIXTURE setup.
|
455
455
|
# So don't bother running it directly from here, but
|
@@ -457,18 +457,10 @@ end # FileList
|
|
457
457
|
# Need a better solution, is there a way to fake the
|
458
458
|
# filesystem?
|
459
459
|
|
460
|
-
=begin #test
|
460
|
+
=begin #no test yet
|
461
461
|
|
462
462
|
require 'test/unit'
|
463
463
|
|
464
|
-
# FIND TEST DIRECTORY
|
465
|
-
paths = File.expand_path(File.dirname(__FILE__)).split('/')
|
466
|
-
paths.size.downto(1) do |i|
|
467
|
-
f = (paths.slice(0..i)+['test']).join('/')
|
468
|
-
$TESTDIR = File.join(f,'FIXTURE') if File.directory?(f)
|
469
|
-
end
|
470
|
-
raise unless $TESTDIR
|
471
|
-
|
472
464
|
class TC_FileList < Test::Unit::TestCase
|
473
465
|
|
474
466
|
def test_filelist
|
data/lib/facets/more/functor.rb
CHANGED
@@ -18,7 +18,7 @@
|
|
18
18
|
# Made a subclass of BasicObject.
|
19
19
|
#
|
20
20
|
# 05-01-10 trans
|
21
|
-
# Ported to
|
21
|
+
# Ported to Facets.
|
22
22
|
# ==========================================================================
|
23
23
|
#++
|
24
24
|
|
@@ -55,12 +55,12 @@ class Functor < BasicObject
|
|
55
55
|
@func = func
|
56
56
|
end
|
57
57
|
|
58
|
-
def method_missing(op, *args)
|
59
|
-
|
60
|
-
|
61
|
-
|
58
|
+
def method_missing(op, *args, &blk)
|
59
|
+
if block_given?
|
60
|
+
@func.call(op, *(@obj + args + [blk]))
|
61
|
+
else
|
62
62
|
@func.call(op, *(@obj + args))
|
63
|
-
|
63
|
+
end
|
64
64
|
end
|
65
65
|
|
66
66
|
def instance_objects
|
@@ -0,0 +1,891 @@
|
|
1
|
+
#--
|
2
|
+
# JSON library for Ruby
|
3
|
+
#
|
4
|
+
# Copyright (c) 2006, Florian Frank
|
5
|
+
#
|
6
|
+
# This is free software; you can redistribute it and/or modify it under the
|
7
|
+
# terms of the GNU General Public License Version 2 as published by the Free
|
8
|
+
# Software Foundation: www.gnu.org/copyleft/gpl.html
|
9
|
+
#
|
10
|
+
# Original Version (0.4.1) Download
|
11
|
+
#
|
12
|
+
# The latest version of this library can be downloaded at
|
13
|
+
#
|
14
|
+
# * http://rubyforge.org/frs?group_id=953
|
15
|
+
#
|
16
|
+
# Online Documentation should be located at
|
17
|
+
#
|
18
|
+
# * http://json.rubyforge.org
|
19
|
+
#++
|
20
|
+
|
21
|
+
($VERSION ||= {})['json'] = '0.4.1'
|
22
|
+
|
23
|
+
# :title: JSON
|
24
|
+
#
|
25
|
+
# Ruby support of Javascript Object Notation.
|
26
|
+
#
|
27
|
+
# == Examples
|
28
|
+
#
|
29
|
+
# To create a JSON string from a ruby data structure, you
|
30
|
+
# can call JSON.unparse like that:
|
31
|
+
#
|
32
|
+
# json = JSON.unparse [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
|
33
|
+
# # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
|
34
|
+
#
|
35
|
+
# It's also possible to call the #to_json method directly.
|
36
|
+
#
|
37
|
+
# json = [1, 2, {"a"=>3.141}, false, true, nil, 4..10].to_json
|
38
|
+
# # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
|
39
|
+
#
|
40
|
+
# To get back a ruby data structure, you have to call
|
41
|
+
# JSON.parse on the JSON string:
|
42
|
+
#
|
43
|
+
# JSON.parse json
|
44
|
+
# # => [1, 2, {"a"=>3.141}, false, true, nil, "4..10"]
|
45
|
+
#
|
46
|
+
# Note, that the range from the original data structure is a simple
|
47
|
+
# string now. The reason for this is, that JSON doesn't support ranges
|
48
|
+
# or arbitrary classes. In this case the json library falls back to call
|
49
|
+
# Object#to_json, which is the same as #to_s.to_json.
|
50
|
+
#
|
51
|
+
# It's possible to extend JSON to support serialization of arbitray classes by
|
52
|
+
# simply implementing a more specialized version of the #to_json method, that
|
53
|
+
# should return a JSON object (a hash converted to JSON with #to_json)
|
54
|
+
# like this (don't forget the *a for all the arguments):
|
55
|
+
#
|
56
|
+
# class Range
|
57
|
+
# def to_json(*a)
|
58
|
+
# {
|
59
|
+
# 'json_class' => self.class.name,
|
60
|
+
# 'data' => [ first, last, exclude_end? ]
|
61
|
+
# }.to_json(*a)
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# The hash key 'json_class' is the class, that will be asked to deserialize the
|
66
|
+
# JSON representation later. In this case it's 'Range', but any namespace of
|
67
|
+
# the form 'A::B' or '::A::B' will do. All other keys are arbitrary and can be
|
68
|
+
# used to store the necessary data to configure the object to be deserialized.
|
69
|
+
#
|
70
|
+
# If a the key 'json_class' is found in a JSON object, the JSON parser checks
|
71
|
+
# if the given class responds to the json_create class method. If so, it is
|
72
|
+
# called with the JSON object converted to a Ruby hash. So a range can
|
73
|
+
# be deserialized by implementing Range.json_create like this:
|
74
|
+
#
|
75
|
+
# class Range
|
76
|
+
# def self.json_create(o)
|
77
|
+
# new(*o['data'])
|
78
|
+
# end
|
79
|
+
# end
|
80
|
+
#
|
81
|
+
# Now it possible to serialize/deserialize ranges as well:
|
82
|
+
#
|
83
|
+
# json = JSON.unparse [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
|
84
|
+
# # => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]"
|
85
|
+
# JSON.parse json
|
86
|
+
# # => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
|
87
|
+
#
|
88
|
+
# JSON.unparse always creates the shortes possible string representation of a
|
89
|
+
# ruby data structure in one line. This good for data storage or network
|
90
|
+
# protocols, but not so good for humans to read. Fortunately there's
|
91
|
+
# also JSON.pretty_unparse that creates a more readable output:
|
92
|
+
#
|
93
|
+
# puts JSON.pretty_unparse([1, 2, {"a"=>3.141}, false, true, nil, 4..10])
|
94
|
+
# [
|
95
|
+
# 1,
|
96
|
+
# 2,
|
97
|
+
# {
|
98
|
+
# "a": 3.141
|
99
|
+
# },
|
100
|
+
# false,
|
101
|
+
# true,
|
102
|
+
# null,
|
103
|
+
# {
|
104
|
+
# "json_class": "Range",
|
105
|
+
# "data": [
|
106
|
+
# 4,
|
107
|
+
# 10,
|
108
|
+
# false
|
109
|
+
# ]
|
110
|
+
# }
|
111
|
+
# ]
|
112
|
+
#
|
113
|
+
# There are also the methods Kernel#j for unparse, and Kernel#jj for
|
114
|
+
# pretty_unparse output to the console, that work analogous to Kernel#p and
|
115
|
+
# Kernel#pp.
|
116
|
+
#
|
117
|
+
# == Author(s)
|
118
|
+
#
|
119
|
+
# Florian Frank <mailto:flori@ping.de>
|
120
|
+
#
|
121
|
+
|
122
|
+
require 'strscan'
|
123
|
+
|
124
|
+
# This module is the namespace for all the JSON related classes. It also
|
125
|
+
# defines some module functions to expose a nicer API to users, instead
|
126
|
+
# of using the parser and other classes directly.
|
127
|
+
|
128
|
+
module JSON
|
129
|
+
|
130
|
+
# The base exception for JSON errors.
|
131
|
+
JSONError = Class.new StandardError
|
132
|
+
|
133
|
+
# This exception is raise, if a parser error occurs.
|
134
|
+
ParserError = Class.new JSONError
|
135
|
+
|
136
|
+
# This exception is raise, if a unparser error occurs.
|
137
|
+
UnparserError = Class.new JSONError
|
138
|
+
|
139
|
+
# If a circular data structure is encountered while unparsing
|
140
|
+
# this exception is raised.
|
141
|
+
CircularDatastructure = Class.new UnparserError
|
142
|
+
|
143
|
+
class << self
|
144
|
+
# Switches on Unicode support, if _enable_ is _true_. Otherwise switches
|
145
|
+
# Unicode support off.
|
146
|
+
def support_unicode=(enable)
|
147
|
+
@support_unicode = enable
|
148
|
+
end
|
149
|
+
|
150
|
+
# Returns _true_ if JSON supports unicode, otherwise _false_ is returned.
|
151
|
+
def support_unicode?
|
152
|
+
!!@support_unicode
|
153
|
+
end
|
154
|
+
end
|
155
|
+
JSON.support_unicode = true # default, hower it's possible to switch off full
|
156
|
+
# unicode support, if non-ascii bytes should be
|
157
|
+
# just passed through.
|
158
|
+
|
159
|
+
begin
|
160
|
+
require 'iconv'
|
161
|
+
# An iconv instance to convert from UTF8 to UTF16 Big Endian.
|
162
|
+
UTF16toUTF8 = Iconv.new('utf-8', 'utf-16be')
|
163
|
+
# An iconv instance to convert from UTF16 Big Endian to UTF8.
|
164
|
+
UTF8toUTF16 = Iconv.new('utf-16be', 'utf-8'); UTF8toUTF16.iconv('no bom')
|
165
|
+
rescue LoadError
|
166
|
+
JSON.support_unicode = false # enforce disabling of unicode support
|
167
|
+
end
|
168
|
+
|
169
|
+
# This class implements the JSON parser that is used to parse a JSON string
|
170
|
+
# into a Ruby data structure.
|
171
|
+
class Parser < StringScanner
|
172
|
+
STRING = /"((?:[^"\\]|\\.)*)"/
|
173
|
+
INTEGER = /-?\d+/
|
174
|
+
FLOAT = /-?\d+\.(\d*)(?i:e[+-]?\d+)?/
|
175
|
+
OBJECT_OPEN = /\{/
|
176
|
+
OBJECT_CLOSE = /\}/
|
177
|
+
ARRAY_OPEN = /\[/
|
178
|
+
ARRAY_CLOSE = /\]/
|
179
|
+
PAIR_DELIMITER = /:/
|
180
|
+
COLLECTION_DELIMITER = /,/
|
181
|
+
TRUE = /true/
|
182
|
+
FALSE = /false/
|
183
|
+
NULL = /null/
|
184
|
+
IGNORE = %r(
|
185
|
+
(?:
|
186
|
+
//[^\n\r]*[\n\r]| # line comments
|
187
|
+
/\* # c-style comments
|
188
|
+
(?:
|
189
|
+
[^*/]| # normal chars
|
190
|
+
/[^*]| # slashes that do not start a nested comment
|
191
|
+
\*[^/]| # asterisks that do not end this comment
|
192
|
+
/(?=\*/) # single slash before this comment's end
|
193
|
+
)*
|
194
|
+
\*/ # the end of this comment
|
195
|
+
|\s+ # whitespaces
|
196
|
+
)+
|
197
|
+
)mx
|
198
|
+
|
199
|
+
UNPARSED = Object.new
|
200
|
+
|
201
|
+
# Parses the current JSON string and returns the complete data structure
|
202
|
+
# as a result.
|
203
|
+
def parse
|
204
|
+
reset
|
205
|
+
until eos?
|
206
|
+
case
|
207
|
+
when scan(ARRAY_OPEN)
|
208
|
+
return parse_array
|
209
|
+
when scan(OBJECT_OPEN)
|
210
|
+
return parse_object
|
211
|
+
when skip(IGNORE)
|
212
|
+
;
|
213
|
+
when !((value = parse_value).equal? UNPARSED)
|
214
|
+
return value
|
215
|
+
else
|
216
|
+
raise ParserError, "source '#{peek(20)}' not in JSON!"
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
private
|
222
|
+
|
223
|
+
def parse_string
|
224
|
+
if scan(STRING)
|
225
|
+
return '' if self[1].empty?
|
226
|
+
self[1].gsub(/\\(?:[\\bfnrt"]|u([A-Fa-f\d]{4}))/) do
|
227
|
+
case $~[0]
|
228
|
+
when '\\\\' then '\\'
|
229
|
+
when '\\b' then "\b"
|
230
|
+
when '\\f' then "\f"
|
231
|
+
when '\\n' then "\n"
|
232
|
+
when '\\r' then "\r"
|
233
|
+
when '\\t' then "\t"
|
234
|
+
when '\\"' then '"'
|
235
|
+
else
|
236
|
+
if JSON.support_unicode? and $KCODE == 'UTF8'
|
237
|
+
JSON.utf16_to_utf8($~[1])
|
238
|
+
else
|
239
|
+
# if utf8 mode is switched off or unicode not supported, try to
|
240
|
+
# transform unicode \u-notation to bytes directly:
|
241
|
+
$~[1].to_i(16).chr
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
else
|
246
|
+
UNPARSED
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def parse_value
|
251
|
+
case
|
252
|
+
when scan(FLOAT)
|
253
|
+
Float(self[0])
|
254
|
+
when scan(INTEGER)
|
255
|
+
Integer(self[0])
|
256
|
+
when scan(TRUE)
|
257
|
+
true
|
258
|
+
when scan(FALSE)
|
259
|
+
false
|
260
|
+
when scan(NULL)
|
261
|
+
nil
|
262
|
+
when (string = parse_string) != UNPARSED
|
263
|
+
string
|
264
|
+
when scan(ARRAY_OPEN)
|
265
|
+
parse_array
|
266
|
+
when scan(OBJECT_OPEN)
|
267
|
+
parse_object
|
268
|
+
else
|
269
|
+
UNPARSED
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def parse_array
|
274
|
+
result = []
|
275
|
+
until eos?
|
276
|
+
case
|
277
|
+
when (value = parse_value) != UNPARSED
|
278
|
+
result << value
|
279
|
+
skip(IGNORE)
|
280
|
+
unless scan(COLLECTION_DELIMITER) or match?(ARRAY_CLOSE)
|
281
|
+
raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!"
|
282
|
+
end
|
283
|
+
when scan(ARRAY_CLOSE)
|
284
|
+
break
|
285
|
+
when skip(IGNORE)
|
286
|
+
;
|
287
|
+
else
|
288
|
+
raise ParserError, "unexpected token in array at '#{peek(20)}'!"
|
289
|
+
end
|
290
|
+
end
|
291
|
+
result
|
292
|
+
end
|
293
|
+
|
294
|
+
def parse_object
|
295
|
+
result = {}
|
296
|
+
until eos?
|
297
|
+
case
|
298
|
+
when (string = parse_string) != UNPARSED
|
299
|
+
skip(IGNORE)
|
300
|
+
unless scan(PAIR_DELIMITER)
|
301
|
+
raise ParserError, "expected ':' in object at '#{peek(20)}'!"
|
302
|
+
end
|
303
|
+
skip(IGNORE)
|
304
|
+
unless (value = parse_value).equal? UNPARSED
|
305
|
+
result[string] = value
|
306
|
+
skip(IGNORE)
|
307
|
+
unless scan(COLLECTION_DELIMITER) or match?(OBJECT_CLOSE)
|
308
|
+
raise ParserError,
|
309
|
+
"expected ',' or '}' in object at '#{peek(20)}'!"
|
310
|
+
end
|
311
|
+
else
|
312
|
+
raise ParserError, "expected value in object at '#{peek(20)}'!"
|
313
|
+
end
|
314
|
+
when scan(OBJECT_CLOSE)
|
315
|
+
if klassname = result['json_class']
|
316
|
+
klass = klassname.sub(/^:+/, '').split(/::/).inject(Object) do |p,k|
|
317
|
+
p.const_get(k) rescue nil
|
318
|
+
end
|
319
|
+
break unless klass and klass.json_creatable?
|
320
|
+
result = klass.json_create(result)
|
321
|
+
end
|
322
|
+
break
|
323
|
+
when skip(IGNORE)
|
324
|
+
;
|
325
|
+
else
|
326
|
+
raise ParserError, "unexpected token in object at '#{peek(20)}'!"
|
327
|
+
end
|
328
|
+
end
|
329
|
+
result
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
# This class is used to create State instances, that are use to hold data
|
334
|
+
# while unparsing a Ruby data structure into a JSON string.
|
335
|
+
class State
|
336
|
+
# Creates a State object from _opts_, which ought to be Hash to create a
|
337
|
+
# new State instance configured by opts, something else to create an
|
338
|
+
# unconfigured instance. If _opts_ is a State object, it is just returned.
|
339
|
+
def self.from_state(opts)
|
340
|
+
case opts
|
341
|
+
when self
|
342
|
+
opts
|
343
|
+
when Hash
|
344
|
+
new(opts)
|
345
|
+
else
|
346
|
+
new
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
# Instantiates a new State object, configured by _opts_.
|
351
|
+
def initialize(opts = {})
|
352
|
+
@indent = opts[:indent] || ''
|
353
|
+
@space = opts[:space] || ''
|
354
|
+
@object_nl = opts[:object_nl] || ''
|
355
|
+
@array_nl = opts[:array_nl] || ''
|
356
|
+
@seen = {}
|
357
|
+
end
|
358
|
+
|
359
|
+
# This string is used to indent levels in the JSON string.
|
360
|
+
attr_accessor :indent
|
361
|
+
|
362
|
+
# This string is used to include a space between the tokens in a JSON
|
363
|
+
# string.
|
364
|
+
attr_accessor :space
|
365
|
+
|
366
|
+
# This string is put at the end of a line that holds a JSON object (or
|
367
|
+
# Hash).
|
368
|
+
attr_accessor :object_nl
|
369
|
+
|
370
|
+
# This string is put at the end of a line that holds a JSON array.
|
371
|
+
attr_accessor :array_nl
|
372
|
+
|
373
|
+
# Returns _true_, if _object_ was already seen during this Unparsing run.
|
374
|
+
def seen?(object)
|
375
|
+
@seen.key?(object.__id__)
|
376
|
+
end
|
377
|
+
|
378
|
+
# Remember _object_, to find out if it was already encountered (to find out
|
379
|
+
# if a cyclic data structure is unparsed).
|
380
|
+
def remember(object)
|
381
|
+
@seen[object.__id__] = true
|
382
|
+
end
|
383
|
+
|
384
|
+
# Forget _object_ for this Unparsing run.
|
385
|
+
def forget(object)
|
386
|
+
@seen.delete object.__id__
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
module_function
|
391
|
+
|
392
|
+
# Convert _string_ from UTF8 encoding to UTF16 (big endian) encoding and
|
393
|
+
# return it.
|
394
|
+
def utf8_to_utf16(string)
|
395
|
+
JSON::UTF8toUTF16.iconv(string).unpack('H*')[0]
|
396
|
+
end
|
397
|
+
|
398
|
+
# Convert _string_ from UTF16 (big endian) encoding to UTF8 encoding and
|
399
|
+
# return it.
|
400
|
+
def utf16_to_utf8(string)
|
401
|
+
bytes = '' << string[0, 2].to_i(16) << string[2, 2].to_i(16)
|
402
|
+
JSON::UTF16toUTF8.iconv(bytes)
|
403
|
+
end
|
404
|
+
|
405
|
+
# Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
|
406
|
+
# UTF16 big endian characters as \u????, and return it.
|
407
|
+
def utf8_to_json(string)
|
408
|
+
i, n, result = 0, string.size, ''
|
409
|
+
while i < n
|
410
|
+
char = string[i]
|
411
|
+
case
|
412
|
+
when char == ?\b then result << '\b'
|
413
|
+
when char == ?\t then result << '\t'
|
414
|
+
when char == ?\n then result << '\n'
|
415
|
+
when char == ?\f then result << '\f'
|
416
|
+
when char == ?\r then result << '\r'
|
417
|
+
when char == ?" then result << '\"'
|
418
|
+
when char == ?\\ then result << '\\\\'
|
419
|
+
when char.between?(0x0, 0x1f) then result << "\\u%04x" % char
|
420
|
+
when char.between?(0x20, 0x7f) then result << char
|
421
|
+
when !(JSON.support_unicode? && $KCODE == 'UTF8')
|
422
|
+
# if utf8 mode is switched off or unicode not supported, just pass
|
423
|
+
# bytes through:
|
424
|
+
result << char
|
425
|
+
when char & 0xe0 == 0xc0
|
426
|
+
result << '\u' << utf8_to_utf16(string[i, 2])
|
427
|
+
i += 1
|
428
|
+
when char & 0xf0 == 0xe0
|
429
|
+
result << '\u' << utf8_to_utf16(string[i, 3])
|
430
|
+
i += 2
|
431
|
+
when char & 0xf8 == 0xf0
|
432
|
+
result << '\u' << utf8_to_utf16(string[i, 4])
|
433
|
+
i += 3
|
434
|
+
when char & 0xfc == 0xf8
|
435
|
+
result << '\u' << utf8_to_utf16(string[i, 5])
|
436
|
+
i += 4
|
437
|
+
when char & 0xfe == 0xfc
|
438
|
+
result << '\u' << utf8_to_utf16(string[i, 6])
|
439
|
+
i += 5
|
440
|
+
else
|
441
|
+
raise JSON::UnparserError, "Encountered unknown UTF-8 byte: %x!" % char
|
442
|
+
end
|
443
|
+
i += 1
|
444
|
+
end
|
445
|
+
result
|
446
|
+
end
|
447
|
+
|
448
|
+
# Parse the JSON string _source_ into a Ruby data structure and return it.
|
449
|
+
def parse(source)
|
450
|
+
Parser.new(source).parse
|
451
|
+
end
|
452
|
+
|
453
|
+
# Unparse the Ruby data structure _obj_ into a single line JSON string and
|
454
|
+
# return it. _state_ is a JSON::State object, that can be used to configure
|
455
|
+
# the output further.
|
456
|
+
def unparse(obj, state = nil)
|
457
|
+
obj.to_json(JSON::State.from_state(state))
|
458
|
+
end
|
459
|
+
|
460
|
+
# Unparse the Ruby data structure _obj_ into a JSON string and return it.
|
461
|
+
# The returned string is a prettier form of the string returned by #unparse.
|
462
|
+
def pretty_unparse(obj)
|
463
|
+
state = JSON::State.new(
|
464
|
+
:indent => ' ',
|
465
|
+
:space => ' ',
|
466
|
+
:object_nl => "\n",
|
467
|
+
:array_nl => "\n"
|
468
|
+
)
|
469
|
+
obj.to_json(state)
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
class Object
|
474
|
+
# Converts this object to a string (calling #to_s), converts
|
475
|
+
# it to a JSON string, and returns the result. This is a fallback, if no
|
476
|
+
# special method #to_json was defined for some object.
|
477
|
+
# _state_ is a JSON::State object, that can also be used
|
478
|
+
# to configure the produced JSON string output further.
|
479
|
+
|
480
|
+
def to_json(*) to_s.to_json end
|
481
|
+
end
|
482
|
+
|
483
|
+
class Hash
|
484
|
+
# Returns a JSON string containing a JSON object, that is unparsed from
|
485
|
+
# this Hash instance.
|
486
|
+
# _state_ is a JSON::State object, that can also be used to configure the
|
487
|
+
# produced JSON string output further.
|
488
|
+
# _depth_ is used to find out nesting depth, to indent accordingly.
|
489
|
+
def to_json(state = nil, depth = 0)
|
490
|
+
state = JSON::State.from_state(state)
|
491
|
+
json_check_circular(state) { json_transform(state, depth) }
|
492
|
+
end
|
493
|
+
|
494
|
+
private
|
495
|
+
|
496
|
+
def json_check_circular(state)
|
497
|
+
if state
|
498
|
+
state.seen?(self) and raise JSON::CircularDatastructure,
|
499
|
+
"circular data structures not supported!"
|
500
|
+
state.remember self
|
501
|
+
end
|
502
|
+
yield
|
503
|
+
ensure
|
504
|
+
state and state.forget self
|
505
|
+
end
|
506
|
+
|
507
|
+
def json_shift(state, depth)
|
508
|
+
state and not state.object_nl.empty? or return ''
|
509
|
+
state.indent * depth
|
510
|
+
end
|
511
|
+
|
512
|
+
def json_transform(state, depth)
|
513
|
+
delim = ','
|
514
|
+
delim << state.object_nl if state
|
515
|
+
result = '{'
|
516
|
+
result << state.object_nl if state
|
517
|
+
result << map { |key,value|
|
518
|
+
json_shift(state, depth + 1) <<
|
519
|
+
key.to_s.to_json(state, depth + 1) <<
|
520
|
+
':' << state.space << value.to_json(state, depth + 1)
|
521
|
+
}.join(delim)
|
522
|
+
result << state.object_nl if state
|
523
|
+
result << json_shift(state, depth)
|
524
|
+
result << '}'
|
525
|
+
result
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
class Array
|
530
|
+
# Returns a JSON string containing a JSON array, that is unparsed from
|
531
|
+
# this Array instance.
|
532
|
+
# _state_ is a JSON::State object, that can also be used to configure the
|
533
|
+
# produced JSON string output further.
|
534
|
+
# _depth_ is used to find out nesting depth, to indent accordingly.
|
535
|
+
def to_json(state = nil, depth = 0)
|
536
|
+
state = JSON::State.from_state(state)
|
537
|
+
json_check_circular(state) { json_transform(state, depth) }
|
538
|
+
end
|
539
|
+
|
540
|
+
private
|
541
|
+
|
542
|
+
def json_check_circular(state)
|
543
|
+
if state
|
544
|
+
state.seen?(self) and raise JSON::CircularDatastructure,
|
545
|
+
"circular data structures not supported!"
|
546
|
+
state.remember self
|
547
|
+
end
|
548
|
+
yield
|
549
|
+
ensure
|
550
|
+
state and state.forget self
|
551
|
+
end
|
552
|
+
|
553
|
+
def json_shift(state, depth)
|
554
|
+
state and not state.array_nl.empty? or return ''
|
555
|
+
state.indent * depth
|
556
|
+
end
|
557
|
+
|
558
|
+
def json_transform(state, depth)
|
559
|
+
delim = ','
|
560
|
+
delim << state.array_nl if state
|
561
|
+
result = '['
|
562
|
+
result << state.array_nl if state
|
563
|
+
result << map { |value|
|
564
|
+
json_shift(state, depth + 1) << value.to_json(state, depth + 1)
|
565
|
+
}.join(delim)
|
566
|
+
result << state.array_nl if state
|
567
|
+
result << json_shift(state, depth)
|
568
|
+
result << ']'
|
569
|
+
result
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
573
|
+
class Integer
|
574
|
+
# Returns a JSON string representation for this Integer number.
|
575
|
+
def to_json(*) to_s end
|
576
|
+
end
|
577
|
+
|
578
|
+
class Float
|
579
|
+
# Returns a JSON string representation for this Float number.
|
580
|
+
def to_json(*) to_s end
|
581
|
+
end
|
582
|
+
|
583
|
+
class String
|
584
|
+
# This string should be encoded with UTF-8 (if JSON unicode support is
|
585
|
+
# enabled). A call to this method returns a JSON string
|
586
|
+
# encoded with UTF16 big endian characters as \u????. If
|
587
|
+
# JSON.support_unicode? is false only control characters are encoded this
|
588
|
+
# way, all 8-bit bytes are just passed through.
|
589
|
+
def to_json(*)
|
590
|
+
'"' << JSON::utf8_to_json(self) << '"'
|
591
|
+
end
|
592
|
+
|
593
|
+
# Raw Strings are JSON Objects (the raw bytes are stored in an array for the
|
594
|
+
# key "raw"). The Ruby String can be created by this class method.
|
595
|
+
def self.json_create(o)
|
596
|
+
o['raw'].pack('C*')
|
597
|
+
end
|
598
|
+
|
599
|
+
# This method creates a raw object, that can be nested into other data
|
600
|
+
# structures and will be unparsed as a raw string.
|
601
|
+
def to_json_raw_object
|
602
|
+
{
|
603
|
+
'json_class' => self.class.name,
|
604
|
+
'raw' => self.unpack('C*'),
|
605
|
+
}
|
606
|
+
end
|
607
|
+
|
608
|
+
# This method should be used, if you want to convert raw strings to JSON
|
609
|
+
# instead of UTF-8 strings, e. g. binary data (and JSON Unicode support is
|
610
|
+
# enabled).
|
611
|
+
def to_json_raw(*args)
|
612
|
+
to_json_raw_object.to_json(*args)
|
613
|
+
end
|
614
|
+
end
|
615
|
+
|
616
|
+
class TrueClass
|
617
|
+
# Returns a JSON string for true: 'true'.
|
618
|
+
def to_json(*) to_s end
|
619
|
+
end
|
620
|
+
|
621
|
+
class FalseClass
|
622
|
+
# Returns a JSON string for false: 'false'.
|
623
|
+
def to_json(*) to_s end
|
624
|
+
end
|
625
|
+
|
626
|
+
class NilClass
|
627
|
+
# Returns a JSON string for nil: 'null'.
|
628
|
+
def to_json(*) 'null' end
|
629
|
+
end
|
630
|
+
|
631
|
+
module Kernel
|
632
|
+
# Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in
|
633
|
+
# one line.
|
634
|
+
def j(*objs)
|
635
|
+
objs.each do |obj|
|
636
|
+
puts JSON::unparse(obj)
|
637
|
+
end
|
638
|
+
nil
|
639
|
+
end
|
640
|
+
|
641
|
+
# Ouputs _objs_ to STDOUT as JSON strings in a pretty format, with
|
642
|
+
# indentation and over many lines.
|
643
|
+
def jj(*objs)
|
644
|
+
objs.each do |obj|
|
645
|
+
puts JSON::pretty_unparse(obj)
|
646
|
+
end
|
647
|
+
nil
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
class Class
|
652
|
+
# Returns true, if this class can be used to create an instance
|
653
|
+
# from a serialised JSON string. The class has to implement a class
|
654
|
+
# method _json_create_ that expects a hash as first parameter, which includes
|
655
|
+
# the required data.
|
656
|
+
def json_creatable?
|
657
|
+
respond_to?(:json_create)
|
658
|
+
end
|
659
|
+
end
|
660
|
+
# vim: set et sw=2 ts=2:
|
661
|
+
|
662
|
+
|
663
|
+
|
664
|
+
|
665
|
+
# _____ _
|
666
|
+
# |_ _|__ ___| |_
|
667
|
+
# | |/ _ \/ __| __|
|
668
|
+
# | | __/\__ \ |_
|
669
|
+
# |_|\___||___/\__|
|
670
|
+
#
|
671
|
+
=begin test
|
672
|
+
|
673
|
+
require 'test/unit'
|
674
|
+
|
675
|
+
class TC_JSON < Test::Unit::TestCase
|
676
|
+
|
677
|
+
include JSON
|
678
|
+
|
679
|
+
class A
|
680
|
+
def initialize(a)
|
681
|
+
@a = a
|
682
|
+
end
|
683
|
+
|
684
|
+
attr_reader :a
|
685
|
+
|
686
|
+
def ==(other)
|
687
|
+
a == other.a
|
688
|
+
end
|
689
|
+
|
690
|
+
def self.json_create(object)
|
691
|
+
new(*object['args'])
|
692
|
+
end
|
693
|
+
|
694
|
+
def to_json(*args)
|
695
|
+
{
|
696
|
+
'json_class' => self.class,
|
697
|
+
'args' => [ @a ],
|
698
|
+
}.to_json(*args)
|
699
|
+
end
|
700
|
+
end
|
701
|
+
|
702
|
+
def setup
|
703
|
+
$KCODE = 'UTF8'
|
704
|
+
@ary = [1, "foo", 3.14, 4711.0, 2.718, nil, [1,-2,3], false, true]
|
705
|
+
@ary_to_parse = ["1", '"foo"', "3.14", "4711.0", "2.718", "null",
|
706
|
+
"[1,-2,3]", "false", "true"]
|
707
|
+
@hash = {
|
708
|
+
'a' => 2,
|
709
|
+
'b' => 3.141,
|
710
|
+
'c' => 'c',
|
711
|
+
'd' => [ 1, "b", 3.14 ],
|
712
|
+
'e' => { 'foo' => 'bar' },
|
713
|
+
'g' => "\"\0\037",
|
714
|
+
'h' => 1000.0,
|
715
|
+
'i' => 0.001
|
716
|
+
}
|
717
|
+
@json = '{"a":2,"b":3.141,"c":"c","d":[1,"b",3.14],"e":{"foo":"bar"},' +
|
718
|
+
'"g":"\\"\\u0000\\u001f","h":1.0E3,"i":1.0E-3}'
|
719
|
+
@json2 = '{"a":2,"b":3.141,"c":"c","d":[1,"b",3.14],"e":{"foo":"bar"},' +
|
720
|
+
'"g":"\\"\\u0000\\u001f","h":1000.0,"i":0.001}'
|
721
|
+
end
|
722
|
+
|
723
|
+
def test_parse_value
|
724
|
+
assert_equal("", parse('""'))
|
725
|
+
assert_equal("\\", parse('"\\\\"'))
|
726
|
+
assert_equal('"', parse('"\""'))
|
727
|
+
assert_equal('\\"\\', parse('"\\\\\\"\\\\"'))
|
728
|
+
assert_equal("\\a\"\b\f\n\r\t\0\037",
|
729
|
+
parse('"\\a\"\b\f\n\r\t\u0000\u001f"'))
|
730
|
+
for i in 0 ... @ary.size
|
731
|
+
assert_equal(@ary[i], parse(@ary_to_parse[i]))
|
732
|
+
end
|
733
|
+
end
|
734
|
+
|
735
|
+
def test_parse_array
|
736
|
+
assert_equal([], parse('[]'))
|
737
|
+
assert_equal([], parse(' [ ] '))
|
738
|
+
assert_equal([1], parse('[1]'))
|
739
|
+
assert_equal([1], parse(' [ 1 ] '))
|
740
|
+
assert_equal(@ary,
|
741
|
+
parse('[1,"foo",3.14,47.11e+2,2718.E-3,null,[1,-2,3],false,true]'))
|
742
|
+
assert_equal(@ary, parse(%Q{ [ 1 , "foo" , 3.14 \t , 47.11e+2
|
743
|
+
, 2718.E-3 ,\n null , [1, -2, 3 ], false , true\n ] }))
|
744
|
+
end
|
745
|
+
|
746
|
+
def test_parse_object
|
747
|
+
assert_equal({}, parse('{}'))
|
748
|
+
assert_equal({}, parse(' { } '))
|
749
|
+
assert_equal({'foo'=>'bar'}, parse('{"foo":"bar"}'))
|
750
|
+
assert_equal({'foo'=>'bar'}, parse(' { "foo" : "bar" } '))
|
751
|
+
end
|
752
|
+
|
753
|
+
def test_unparse
|
754
|
+
json = unparse(@hash)
|
755
|
+
assert_equal(@json2, json)
|
756
|
+
parsed_json = parse(json)
|
757
|
+
assert_equal(@hash, parsed_json)
|
758
|
+
json = unparse({1=>2})
|
759
|
+
assert_equal('{"1":2}', json)
|
760
|
+
parsed_json = parse(json)
|
761
|
+
assert_equal({"1"=>2}, parsed_json)
|
762
|
+
end
|
763
|
+
|
764
|
+
def test_parser_reset
|
765
|
+
parser = Parser.new(@json)
|
766
|
+
assert_equal(@hash, parser.parse)
|
767
|
+
assert_equal(@hash, parser.parse)
|
768
|
+
end
|
769
|
+
|
770
|
+
def test_unicode
|
771
|
+
assert_equal '""', ''.to_json
|
772
|
+
assert_equal '"\\b"', "\b".to_json
|
773
|
+
assert_equal '"\u0001"', 0x1.chr.to_json
|
774
|
+
assert_equal '"\u001f"', 0x1f.chr.to_json
|
775
|
+
assert_equal '" "', ' '.to_json
|
776
|
+
assert_equal "\"#{0x7f.chr}\"", 0x7f.chr.to_json
|
777
|
+
utf8 = '© ≠ €!'
|
778
|
+
json = '"\u00a9 \u2260 \u20ac!"'
|
779
|
+
assert_equal json, utf8.to_json
|
780
|
+
assert_equal utf8, parse(json)
|
781
|
+
utf8 = "\343\201\202\343\201\204\343\201\206\343\201\210\343\201\212"
|
782
|
+
json = '"\u3042\u3044\u3046\u3048\u304a"'
|
783
|
+
assert_equal json, utf8.to_json
|
784
|
+
assert_equal utf8, parse(json)
|
785
|
+
utf8 = 'საქართველო'
|
786
|
+
json = '"\u10e1\u10d0\u10e5\u10d0\u10e0\u10d7\u10d5\u10d4\u10da\u10dd"'
|
787
|
+
assert_equal json, utf8.to_json
|
788
|
+
assert_equal utf8, parse(json)
|
789
|
+
end
|
790
|
+
|
791
|
+
def test_comments
|
792
|
+
json = <<EOT
|
793
|
+
{
|
794
|
+
"key1":"value1", // eol comment
|
795
|
+
"key2":"value2" /* multi line
|
796
|
+
* comment */,
|
797
|
+
"key3":"value3" /* multi line
|
798
|
+
// nested eol comment
|
799
|
+
* comment */
|
800
|
+
}
|
801
|
+
EOT
|
802
|
+
assert_equal(
|
803
|
+
{ "key1" => "value1", "key2" => "value2", "key3" => "value3" },
|
804
|
+
parse(json))
|
805
|
+
json = <<EOT
|
806
|
+
{
|
807
|
+
"key1":"value1" /* multi line
|
808
|
+
// nested eol comment
|
809
|
+
/* illegal nested multi line comment */
|
810
|
+
* comment */
|
811
|
+
}
|
812
|
+
EOT
|
813
|
+
assert_raises(ParserError) { parse(json) }
|
814
|
+
json = <<EOT
|
815
|
+
{
|
816
|
+
"key1":"value1" /* multi line
|
817
|
+
// nested eol comment
|
818
|
+
closed multi comment */
|
819
|
+
and again, throw an Error */
|
820
|
+
}
|
821
|
+
EOT
|
822
|
+
assert_raises(ParserError) { parse(json) }
|
823
|
+
json = <<EOT
|
824
|
+
{
|
825
|
+
"key1":"value1" /*/*/
|
826
|
+
}
|
827
|
+
EOT
|
828
|
+
assert_equal({ "key1" => "value1" }, parse(json))
|
829
|
+
end
|
830
|
+
|
831
|
+
def test_extended_json
|
832
|
+
a = A.new(666)
|
833
|
+
json = a.to_json
|
834
|
+
a_again = JSON.parse(json)
|
835
|
+
assert_kind_of a.class, a_again
|
836
|
+
assert_equal a, a_again
|
837
|
+
end
|
838
|
+
|
839
|
+
def test_raw_strings
|
840
|
+
raw = ''
|
841
|
+
raw_array = []
|
842
|
+
for i in 0..255
|
843
|
+
raw << i
|
844
|
+
raw_array << i
|
845
|
+
end
|
846
|
+
json = raw.to_json_raw
|
847
|
+
json_raw_object = raw.to_json_raw_object
|
848
|
+
hash = { 'json_class' => 'String', 'raw'=> raw_array }
|
849
|
+
assert_equal hash, json_raw_object
|
850
|
+
json_raw = <<EOT.chomp
|
851
|
+
{\"json_class\":\"String\",\"raw\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255]}
|
852
|
+
EOT
|
853
|
+
# "
|
854
|
+
assert_equal json_raw, json
|
855
|
+
raw_again = JSON.parse(json)
|
856
|
+
assert_equal raw, raw_again
|
857
|
+
end
|
858
|
+
|
859
|
+
def test_utf8_mode
|
860
|
+
$KCODE = 'NONE'
|
861
|
+
utf8 = "© ≠ €! - \001"
|
862
|
+
json = "\"© ≠ €! - \\u0001\""
|
863
|
+
assert_equal json, utf8.to_json
|
864
|
+
assert_equal utf8, parse(json)
|
865
|
+
assert JSON.support_unicode?
|
866
|
+
$KCODE = 'UTF8'
|
867
|
+
utf8 = '© ≠ €!'
|
868
|
+
json = '"\u00a9 \u2260 \u20ac!"'
|
869
|
+
assert_equal json, utf8.to_json
|
870
|
+
assert_equal utf8, parse(json)
|
871
|
+
JSON.support_unicode = false
|
872
|
+
assert !JSON.support_unicode?
|
873
|
+
utf8 = "© ≠ €! - \001"
|
874
|
+
json = "\"© ≠ €! - \\u0001\""
|
875
|
+
assert_equal json, utf8.to_json
|
876
|
+
assert_equal utf8, parse(json)
|
877
|
+
end
|
878
|
+
|
879
|
+
def test_backslash
|
880
|
+
json = '"\\\\.(?i:gif|jpe?g|png)$"'
|
881
|
+
data = JSON.parse(json)
|
882
|
+
assert_equal json, JSON.unparse(data)
|
883
|
+
json = '"\\""'
|
884
|
+
data = JSON.parse(json)
|
885
|
+
assert_equal json, JSON.unparse(data)
|
886
|
+
end
|
887
|
+
end
|
888
|
+
|
889
|
+
=end
|
890
|
+
|
891
|
+
# vim: set et sw=2 ts=2:
|