facets 1.1.0 → 1.2.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/AUTHORS +5 -2
- data/ProjectInfo +21 -12
- data/README +73 -44
- data/Rakefile +11 -11
- data/data/facets/index.yml +1 -0
- data/lib/facet/annotation.rb +1 -0
- data/lib/facet/ansicode.rb +1 -0
- data/lib/facet/array.rb +1 -34
- data/lib/facet/array/at_rand.rb +1 -52
- data/lib/facet/array/body.rb +1 -2
- data/lib/facet/array/delete_unless.rb +1 -35
- data/lib/facet/array/delete_values.rb +1 -38
- data/lib/facet/array/delete_values_at.rb +1 -57
- data/lib/facet/array/each_with_key.rb +1 -9
- data/lib/facet/array/first.rb +1 -84
- data/lib/facet/array/foot.rb +1 -2
- data/lib/facet/array/head.rb +1 -80
- data/lib/facet/array/last.rb +1 -2
- data/lib/facet/array/last_index.rb +1 -35
- data/lib/facet/array/merge.rb +1 -40
- data/lib/facet/array/mid.rb +1 -50
- data/lib/facet/array/middle.rb +1 -45
- data/lib/facet/array/op_fetch.rb +1 -40
- data/lib/facet/array/op_mod.rb +1 -16
- data/lib/facet/array/op_store.rb +1 -47
- data/lib/facet/array/pick.rb +1 -68
- data/lib/facet/array/pos.rb +1 -39
- data/lib/facet/array/pull.rb +1 -37
- data/lib/facet/array/rand_index.rb +1 -30
- data/lib/facet/array/rand_subset.rb +1 -56
- data/lib/facet/array/range.rb +1 -47
- data/lib/facet/array/rotate.rb +1 -67
- data/lib/facet/array/select.rb +1 -37
- data/lib/facet/array/shuffle.rb +1 -66
- data/lib/facet/array/slap.rb +1 -37
- data/lib/facet/array/store.rb +1 -7
- data/lib/facet/array/tail.rb +1 -2
- data/lib/facet/array/thru.rb +1 -38
- data/lib/facet/array/to_b.rb +1 -31
- data/lib/facet/array/to_h.rb +1 -57
- data/lib/facet/array/to_hash.rb +1 -46
- data/lib/facet/array/unzip.rb +1 -20
- data/lib/facet/association.rb +1 -0
- data/lib/facet/basicobject.rb +1 -0
- data/lib/facet/bbcode.rb +1 -0
- data/lib/facet/binaryreader.rb +1 -0
- data/lib/facet/binding.rb +1 -14
- data/lib/facet/binding/__DIR__.rb +1 -2
- data/lib/facet/binding/__FILE__.rb +1 -2
- data/lib/facet/binding/__LINE__.rb +1 -58
- data/lib/facet/binding/call_stack.rb +1 -42
- data/lib/facet/binding/called.rb +1 -41
- data/lib/facet/binding/caller.rb +1 -42
- data/lib/facet/binding/defined.rb +1 -41
- data/lib/facet/binding/eval.rb +1 -42
- data/lib/facet/binding/local_variables.rb +1 -45
- data/lib/facet/binding/method_name.rb +1 -48
- data/lib/facet/binding/op_fetch.rb +1 -45
- data/lib/facet/binding/op_store.rb +1 -46
- data/lib/facet/binding/self.rb +1 -41
- data/lib/facet/binding/self/of_caller.rb +1 -122
- data/lib/facet/bitmask.rb +1 -0
- data/lib/facet/blankslate.rb +1 -0
- data/lib/facet/bytes.rb +1 -0
- data/lib/facet/class.rb +1 -7
- data/lib/facet/class/by_name.rb +1 -1
- data/lib/facet/class/descendents.rb +1 -44
- data/lib/facet/class/method_name.rb +1 -33
- data/lib/facet/class/remove_descendents.rb +1 -46
- data/lib/facet/class/remove_subclasses.rb +1 -2
- data/lib/facet/class/subclasses.rb +1 -2
- data/lib/facet/class/unix_path.rb +1 -34
- data/lib/facet/classinherit.rb +1 -0
- data/lib/facet/classmethods.rb +1 -0
- data/lib/facet/cloneable.rb +1 -0
- data/lib/facet/comparable.rb +1 -5
- data/lib/facet/comparable/at_least.rb +1 -53
- data/lib/facet/comparable/at_most.rb +1 -2
- data/lib/facet/comparable/cap.rb +1 -2
- data/lib/facet/comparable/clip.rb +1 -72
- data/lib/facet/comparable/cmp.rb +1 -38
- data/lib/facet/consoleapp.rb +1 -0
- data/lib/facet/continuation.rb +1 -1
- data/lib/facet/continuation/self/create.rb +1 -71
- data/lib/facet/coroutine.rb +1 -0
- data/lib/facet/crypt.rb +1 -0
- data/lib/facet/date.rb +1 -0
- data/lib/facet/date/days_in_month.rb +1 -42
- data/lib/facet/date/days_of_month.rb +1 -34
- data/lib/facet/date/stamp.rb +1 -52
- data/lib/facet/date/to_date.rb +1 -36
- data/lib/facet/date/to_s.rb +1 -33
- data/lib/facet/date/to_time.rb +1 -36
- data/lib/facet/dictionary.rb +1 -0
- data/lib/facet/dir.rb +1 -4
- data/lib/facet/dir/self/ancestor.rb +1 -33
- data/lib/facet/dir/self/ascend.rb +1 -56
- data/lib/facet/dir/self/ls_r.rb +1 -76
- data/lib/facet/dir/self/recurse.rb +1 -2
- data/lib/facet/downloader.rb +1 -0
- data/lib/facet/enumerable.rb +1 -39
- data/lib/facet/enumerable/collect_with_counter.rb +1 -2
- data/lib/facet/enumerable/collect_with_index.rb +1 -51
- data/lib/facet/enumerable/commonality.rb +1 -63
- data/lib/facet/enumerable/compact_collect.rb +1 -50
- data/lib/facet/enumerable/compact_map.rb +1 -2
- data/lib/facet/enumerable/cross.rb +1 -44
- data/lib/facet/enumerable/each_by.rb +1 -2
- data/lib/facet/enumerable/each_combination.rb +1 -59
- data/lib/facet/enumerable/each_pair.rb +1 -50
- data/lib/facet/enumerable/each_permutation.rb +1 -2
- data/lib/facet/enumerable/each_slice.rb +1 -131
- data/lib/facet/enumerable/each_unique_pair.rb +1 -66
- data/lib/facet/enumerable/each_with_counter.rb +1 -8
- data/lib/facet/enumerable/elementwise.rb +1 -2
- data/lib/facet/enumerable/entropy.rb +1 -52
- data/lib/facet/enumerable/every.rb +1 -65
- data/lib/facet/enumerable/ew.rb +1 -64
- data/lib/facet/enumerable/filter_collect.rb +1 -58
- data/lib/facet/enumerable/filter_map.rb +1 -2
- data/lib/facet/enumerable/find_collisions.rb +1 -41
- data/lib/facet/enumerable/frequency.rb +1 -39
- data/lib/facet/enumerable/graph.rb +1 -59
- data/lib/facet/enumerable/ideal_entropy.rb +1 -49
- data/lib/facet/enumerable/map_with_counter.rb +1 -2
- data/lib/facet/enumerable/map_with_index.rb +1 -2
- data/lib/facet/enumerable/none.rb +1 -56
- data/lib/facet/enumerable/nonuniq.rb +1 -39
- data/lib/facet/enumerable/occur.rb +1 -62
- data/lib/facet/enumerable/one.rb +1 -65
- data/lib/facet/enumerable/op_pow.rb +1 -38
- data/lib/facet/enumerable/partition_by.rb +1 -55
- data/lib/facet/enumerable/permute.rb +1 -135
- data/lib/facet/enumerable/probability.rb +1 -59
- data/lib/facet/enumerable/project.rb +1 -11
- data/lib/facet/enumerable/self/combinations.rb +1 -68
- data/lib/facet/enumerable/self/cross.rb +1 -79
- data/lib/facet/enumerable/to_h.rb +1 -50
- data/lib/facet/enumerable/uniq_by.rb +1 -39
- data/lib/facet/enumerable/where.rb +1 -12
- data/lib/facet/enumerablepass.rb +1 -0
- data/lib/facet/expirable.rb +1 -0
- data/lib/facet/file.rb +1 -5
- data/lib/facet/file/self/create.rb +1 -52
- data/lib/facet/file/self/open_as_string.rb +1 -81
- data/lib/facet/file/self/read_list.rb +1 -47
- data/lib/facet/file/self/sanitize.rb +1 -50
- data/lib/facet/file/self/split_all.rb +1 -36
- data/lib/facet/filelist.rb +1 -0
- data/lib/facet/fileutils.rb +1 -0
- data/lib/facet/fileutils/head.rb +1 -2
- data/lib/facet/fileutils/safe_ln.rb +1 -38
- data/lib/facet/fileutils/slice.rb +1 -152
- data/lib/facet/fileutils/split_all.rb +1 -29
- data/lib/facet/fileutils/tail.rb +1 -2
- data/lib/facet/fileutils/wc.rb +1 -128
- data/lib/facet/fileutils/whereis.rb +1 -76
- data/lib/facet/fileutils/which.rb +1 -117
- data/lib/facet/float.rb +1 -3
- data/lib/facet/float/approx.rb +1 -42
- data/lib/facet/float/round_at.rb +1 -72
- data/lib/facet/float/round_to.rb +1 -73
- data/lib/facet/floatstring.rb +1 -0
- data/lib/facet/functor.rb +1 -41
- data/lib/facet/gem.rb +1 -3
- data/lib/facet/gem/self/active.rb +1 -9
- data/lib/facet/gem/self/gempath.rb +1 -10
- data/lib/facet/gem/self/gemspec.rb +1 -10
- data/lib/facet/hash.rb +1 -40
- data/lib/facet/hash/alias.rb +1 -54
- data/lib/facet/hash/assert_has_keys.rb +1 -38
- data/lib/facet/hash/assert_has_only_keys.rb +1 -38
- data/lib/facet/hash/at.rb +1 -26
- data/lib/facet/hash/collate.rb +1 -53
- data/lib/facet/hash/delete_unless.rb +1 -15
- data/lib/facet/hash/each.rb +1 -61
- data/lib/facet/hash/each_with_index.rb +1 -35
- data/lib/facet/hash/each_with_key.rb +1 -32
- data/lib/facet/hash/graph.rb +1 -31
- data/lib/facet/hash/has_keys.rb +1 -37
- data/lib/facet/hash/has_only_keys.rb +1 -37
- data/lib/facet/hash/inverse.rb +1 -51
- data/lib/facet/hash/join.rb +1 -19
- data/lib/facet/hash/keys_to_iv.rb +1 -60
- data/lib/facet/hash/keys_to_s.rb +1 -80
- data/lib/facet/hash/keys_to_sym.rb +1 -91
- data/lib/facet/hash/op_fetch.rb +1 -146
- data/lib/facet/hash/op_lshift.rb +1 -28
- data/lib/facet/hash/op_store.rb +1 -2
- data/lib/facet/hash/rand_key.rb +1 -47
- data/lib/facet/hash/rand_pair.rb +1 -50
- data/lib/facet/hash/rand_value.rb +1 -60
- data/lib/facet/hash/replace_each.rb +1 -33
- data/lib/facet/hash/self/zipnew.rb +1 -37
- data/lib/facet/hash/shuffle.rb +1 -53
- data/lib/facet/hash/slice.rb +1 -33
- data/lib/facet/hash/stringify_keys.rb +1 -2
- data/lib/facet/hash/swap.rb +1 -36
- data/lib/facet/hash/swapkey.rb +1 -44
- data/lib/facet/hash/symoblize_keys.rb +1 -2
- data/lib/facet/hash/to_h.rb +1 -35
- data/lib/facet/hash/to_ostruct.rb +1 -40
- data/lib/facet/hash/to_ostruct_recurse.rb +1 -45
- data/lib/facet/hash/traverse.rb +1 -63
- data/lib/facet/hash/update_each.rb +1 -43
- data/lib/facet/hash/update_keys.rb +1 -31
- data/lib/facet/hash/update_values.rb +1 -32
- data/lib/facet/hash/variablize_keys.rb +1 -2
- data/lib/facet/hash/weave.rb +1 -88
- data/lib/facet/heap.rb +1 -0
- data/lib/facet/inflect.rb +1 -70
- data/lib/facet/inheritor.rb +1 -0
- data/lib/facet/integer.rb +1 -9
- data/lib/facet/integer/even.rb +1 -2
- data/lib/facet/integer/fac.rb +1 -2
- data/lib/facet/integer/fact.rb +1 -2
- data/lib/facet/integer/factorial.rb +1 -61
- data/lib/facet/integer/multiple.rb +1 -69
- data/lib/facet/integer/odd.rb +1 -2
- data/lib/facet/integer/ordinal.rb +1 -41
- data/lib/facet/integer/times_collect.rb +1 -39
- data/lib/facet/integer/times_map.rb +1 -2
- data/lib/facet/interval.rb +1 -0
- data/lib/facet/ioredirect.rb +1 -0
- data/lib/facet/kernel.rb +1 -68
- data/lib/facet/kernel/__DIR__.rb +1 -11
- data/lib/facet/kernel/__class__.rb +1 -31
- data/lib/facet/kernel/__meta__.rb +1 -28
- data/lib/facet/kernel/adhoc.rb +1 -11
- data/lib/facet/kernel/as.rb +1 -91
- data/lib/facet/kernel/assign_from.rb +1 -82
- data/lib/facet/kernel/assign_with.rb +1 -75
- data/lib/facet/kernel/autoreload.rb +1 -124
- data/lib/facet/kernel/autoreload_files.rb +1 -2
- data/lib/facet/kernel/autoreload_glob.rb +1 -3
- data/lib/facet/kernel/bool.rb +1 -77
- data/lib/facet/kernel/bug.rb +1 -39
- data/lib/facet/kernel/call_stack.rb +1 -59
- data/lib/facet/kernel/called.rb +1 -40
- data/lib/facet/kernel/complete.rb +1 -6
- data/lib/facet/kernel/constant.rb +1 -52
- data/lib/facet/kernel/copy.rb +1 -48
- data/lib/facet/kernel/deep_copy.rb +1 -49
- data/lib/facet/kernel/demo.rb +1 -46
- data/lib/facet/kernel/eigenclass.rb +1 -17
- data/lib/facet/kernel/false.rb +1 -2
- data/lib/facet/kernel/fn.rb +1 -33
- data/lib/facet/kernel/generate_method_name.rb +1 -39
- data/lib/facet/kernel/get_by_id.rb +1 -33
- data/lib/facet/kernel/here.rb +1 -34
- data/lib/facet/kernel/in.rb +1 -35
- data/lib/facet/kernel/instance_assign.rb +1 -25
- data/lib/facet/kernel/instvar.rb +1 -13
- data/lib/facet/kernel/is.rb +1 -5
- data/lib/facet/kernel/maybe.rb +1 -41
- data/lib/facet/kernel/me.rb +1 -17
- data/lib/facet/kernel/meta.rb +1 -2
- data/lib/facet/kernel/metaclass.rb +1 -42
- data/lib/facet/kernel/method.rb +1 -76
- data/lib/facet/kernel/method_name.rb +1 -49
- data/lib/facet/kernel/methods.rb +1 -79
- data/lib/facet/kernel/nack.rb +1 -12
- data/lib/facet/kernel/new.rb +1 -40
- data/lib/facet/kernel/object_class.rb +1 -31
- data/lib/facet/kernel/object_hexid.rb +1 -35
- data/lib/facet/kernel/op_esc.rb +1 -37
- data/lib/facet/kernel/own.rb +1 -17
- data/lib/facet/kernel/p.rb +1 -12
- data/lib/facet/kernel/require_all.rb +1 -44
- data/lib/facet/kernel/require_esc.rb +1 -42
- data/lib/facet/kernel/require_facet.rb +1 -41
- data/lib/facet/kernel/require_local.rb +1 -25
- data/lib/facet/kernel/resc.rb +1 -32
- data/lib/facet/kernel/returning.rb +1 -49
- data/lib/facet/kernel/send_as.rb +1 -34
- data/lib/facet/kernel/set_from.rb +1 -69
- data/lib/facet/kernel/set_with.rb +1 -74
- data/lib/facet/kernel/silence_warnings.rb +1 -2
- data/lib/facet/kernel/silently.rb +1 -41
- data/lib/facet/kernel/singleton.rb +1 -47
- data/lib/facet/kernel/superior.rb +1 -53
- data/lib/facet/kernel/supermethod.rb +1 -44
- data/lib/facet/kernel/this.rb +1 -33
- data/lib/facet/kernel/to_b.rb +1 -41
- data/lib/facet/kernel/to_bool.rb +1 -47
- data/lib/facet/kernel/true.rb +1 -2
- data/lib/facet/kernel/unuri.rb +1 -2
- data/lib/facet/kernel/uri.rb +1 -38
- data/lib/facet/kernel/val.rb +1 -52
- data/lib/facet/kernel/warn_with_line.rb +1 -30
- data/lib/facet/kernel/with_accessor.rb +1 -94
- data/lib/facet/kernel/with_reader.rb +1 -2
- data/lib/facet/kernel/with_writer.rb +1 -2
- data/lib/facet/lisp.rb +1 -0
- data/lib/facet/lisp_format.rb +1 -0
- data/lib/facet/logger.rb +1 -0
- data/lib/facet/logger/format.rb +1 -28
- data/lib/facet/logger/format_message.rb +1 -1
- data/lib/facet/lrucache.rb +1 -0
- data/lib/facet/matchdata.rb +1 -3
- data/lib/facet/matchdata/match.rb +1 -37
- data/lib/facet/matchdata/matchset.rb +1 -2
- data/lib/facet/matchdata/matchtree.rb +1 -62
- data/lib/facet/mathconstants.rb +1 -0
- data/lib/facet/methodprobe.rb +1 -0
- data/lib/facet/mock.rb +1 -0
- data/lib/facet/module.rb +1 -40
- data/lib/facet/module/abstract.rb +1 -50
- data/lib/facet/module/alias_module_function.rb +1 -57
- data/lib/facet/module/ancestor.rb +1 -38
- data/lib/facet/module/attr.rb +1 -23
- data/lib/facet/module/attr_setter.rb +1 -48
- data/lib/facet/module/attr_tester.rb +1 -56
- data/lib/facet/module/basename.rb +1 -39
- data/lib/facet/module/by_name.rb +1 -68
- data/lib/facet/module/cattr_accessor.rb +1 -141
- data/lib/facet/module/cattr_reader.rb +1 -2
- data/lib/facet/module/cattr_writer.rb +1 -2
- data/lib/facet/module/clone_removing.rb +1 -2
- data/lib/facet/module/clone_renaming.rb +1 -2
- data/lib/facet/module/clone_using.rb +1 -87
- data/lib/facet/module/dirname.rb +1 -42
- data/lib/facet/module/equate_on.rb +1 -70
- data/lib/facet/module/generate_instance_method_name.rb +1 -47
- data/lib/facet/module/include_as.rb +1 -102
- data/lib/facet/module/initializer.rb +1 -65
- data/lib/facet/module/instance_methods.rb +1 -186
- data/lib/facet/module/integrate.rb +1 -51
- data/lib/facet/module/is.rb +1 -34
- data/lib/facet/module/memoize.rb +1 -95
- data/lib/facet/module/modspace.rb +1 -43
- data/lib/facet/module/namespace.rb +1 -61
- data/lib/facet/module/nesting.rb +1 -45
- data/lib/facet/module/redef.rb +1 -31
- data/lib/facet/module/redefine_method.rb +1 -57
- data/lib/facet/module/redirect.rb +1 -30
- data/lib/facet/module/redirect_method.rb +1 -64
- data/lib/facet/module/remove.rb +1 -29
- data/lib/facet/module/rename.rb +1 -31
- data/lib/facet/module/rename_method.rb +1 -38
- data/lib/facet/module/revisal.rb +1 -49
- data/lib/facet/module/shadow_all.rb +1 -17
- data/lib/facet/module/shadow_method.rb +1 -42
- data/lib/facet/module/sort_on.rb +1 -73
- data/lib/facet/module/undef.rb +1 -29
- data/lib/facet/module/wrap.rb +1 -30
- data/lib/facet/module/wrap_method.rb +1 -48
- data/lib/facet/multipliers.rb +1 -0
- data/lib/facet/multiton.rb +1 -0
- data/lib/facet/nackclass.rb +1 -0
- data/lib/facet/nil_as_emptiness.rb +1 -34
- data/lib/facet/nilclass.rb +1 -7
- data/lib/facet/nilclass/empty.rb +1 -32
- data/lib/facet/nilclass/include.rb +1 -32
- data/lib/facet/nilclass/length.rb +1 -2
- data/lib/facet/nilclass/op_fetch.rb +1 -37
- data/lib/facet/nilclass/size.rb +1 -44
- data/lib/facet/nilclass/to_f.rb +1 -32
- data/lib/facet/nilclass/to_h.rb +1 -33
- data/lib/facet/nilcomparable.rb +1 -0
- data/lib/facet/nullclass.rb +1 -0
- data/lib/facet/numeric.rb +1 -5
- data/lib/facet/numeric/ceil_multiple.rb +1 -40
- data/lib/facet/numeric/pred.rb +1 -2
- data/lib/facet/numeric/succ.rb +1 -69
- data/lib/facet/numeric/to_b.rb +1 -38
- data/lib/facet/one.rb +1 -0
- data/lib/facet/openobject.rb +1 -0
- data/lib/facet/orderedhash.rb +1 -0
- data/lib/facet/ormsupport.rb +1 -0
- data/lib/facet/ostruct.rb +1 -0
- data/lib/facet/ostruct/__merge__.rb +1 -52
- data/lib/facet/ostruct/__table__.rb +1 -17
- data/lib/facet/ostruct/__update__.rb +1 -45
- data/lib/facet/ostruct/op_fetch.rb +1 -40
- data/lib/facet/ostruct/op_store.rb +1 -42
- data/lib/facet/ostruct/to_h.rb +1 -8
- data/lib/facet/overload.rb +1 -0
- data/lib/facet/paramix.rb +1 -0
- data/lib/facet/pathlist.rb +1 -0
- data/lib/facet/pathname.rb +1 -2
- data/lib/facet/pathname/ascend.rb +1 -22
- data/lib/facet/pathname/descend.rb +1 -20
- data/lib/facet/pool.rb +1 -0
- data/lib/facet/preinitialize.rb +1 -0
- data/lib/facet/proc.rb +1 -3
- data/lib/facet/proc/compose.rb +1 -62
- data/lib/facet/proc/op_mul.rb +1 -2
- data/lib/facet/proc/to_method.rb +1 -74
- data/lib/facet/progressbar.rb +1 -0
- data/lib/facet/promoteself.rb +1 -0
- data/lib/facet/quaternion.rb +1 -0
- data/lib/facet/random.rb +1 -21
- data/lib/facet/range.rb +1 -4
- data/lib/facet/range/to_r.rb +1 -32
- data/lib/facet/range/to_range.rb +1 -36
- data/lib/facet/range/umbrella.rb +1 -67
- data/lib/facet/range/within.rb +1 -44
- data/lib/facet/reference.rb +1 -0
- data/lib/facet/regexp.rb +1 -3
- data/lib/facet/regexp/arity.rb +1 -41
- data/lib/facet/regexp/to_re.rb +1 -38
- data/lib/facet/regexp/to_regexp.rb +1 -36
- data/lib/facet/rtals.rb +1 -0
- data/lib/facet/semaphore.rb +1 -0
- data/lib/facet/snapshot.rb +1 -0
- data/lib/facet/stateparser.rb +1 -0
- data/lib/facet/statichash.rb +1 -0
- data/lib/facet/string.rb +1 -91
- data/lib/facet/string/align_center.rb +1 -87
- data/lib/facet/string/align_left.rb +1 -2
- data/lib/facet/string/align_right.rb +1 -2
- data/lib/facet/string/at.rb +1 -8
- data/lib/facet/string/at_rand.rb +1 -65
- data/lib/facet/string/basename.rb +1 -48
- data/lib/facet/string/blank.rb +1 -36
- data/lib/facet/string/bracket.rb +1 -70
- data/lib/facet/string/brief.rb +1 -33
- data/lib/facet/string/bytes.rb +1 -19
- data/lib/facet/string/camelcase.rb +1 -58
- data/lib/facet/string/camelize.rb +1 -35
- data/lib/facet/string/capitalized.rb +1 -38
- data/lib/facet/string/chars.rb +1 -34
- data/lib/facet/string/cmp.rb +1 -43
- data/lib/facet/string/demodulize.rb +1 -40
- data/lib/facet/string/dequote.rb +1 -29
- data/lib/facet/string/downcase.rb +1 -37
- data/lib/facet/string/dresner.rb +1 -49
- data/lib/facet/string/each_char.rb +1 -35
- data/lib/facet/string/each_word.rb +1 -50
- data/lib/facet/string/ends_with.rb +1 -2
- data/lib/facet/string/first.rb +1 -94
- data/lib/facet/string/first_char.rb +1 -20
- data/lib/facet/string/fold.rb +1 -67
- data/lib/facet/string/format.rb +1 -17
- data/lib/facet/string/frequency.rb +1 -39
- data/lib/facet/string/humanize.rb +1 -31
- data/lib/facet/string/indent.rb +1 -68
- data/lib/facet/string/index_all.rb +1 -40
- data/lib/facet/string/last.rb +1 -94
- data/lib/facet/string/last_char.rb +1 -22
- data/lib/facet/string/line_wrap.rb +1 -77
- data/lib/facet/string/lines.rb +1 -33
- data/lib/facet/string/lowercase.rb +1 -32
- data/lib/facet/string/margin.rb +1 -138
- data/lib/facet/string/methodize.rb +1 -44
- data/lib/facet/string/modulize.rb +1 -44
- data/lib/facet/string/mscan.rb +1 -42
- data/lib/facet/string/natcmp.rb +1 -108
- data/lib/facet/string/nchar.rb +1 -45
- data/lib/facet/string/ordinal.rb +1 -16
- data/lib/facet/string/pathize.rb +1 -46
- data/lib/facet/string/plural.rb +1 -2
- data/lib/facet/string/pop.rb +1 -54
- data/lib/facet/string/probability.rb +1 -34
- data/lib/facet/string/pull.rb +1 -17
- data/lib/facet/string/push.rb +1 -44
- data/lib/facet/string/quote.rb +1 -68
- data/lib/facet/string/rand_byte.rb +1 -55
- data/lib/facet/string/rand_index.rb +1 -29
- data/lib/facet/string/range.rb +1 -37
- data/lib/facet/string/range_all.rb +1 -48
- data/lib/facet/string/range_of_line.rb +1 -42
- data/lib/facet/string/regesc.rb +1 -32
- data/lib/facet/string/self/format.rb +1 -17
- data/lib/facet/string/self/interpolate.rb +1 -31
- data/lib/facet/string/self/patterns.rb +1 -51
- data/lib/facet/string/self/rand_letter.rb +1 -34
- data/lib/facet/string/self/random.rb +1 -37
- data/lib/facet/string/shatter.rb +1 -45
- data/lib/facet/string/shell_escape.rb +1 -0
- data/lib/facet/string/shift.rb +1 -42
- data/lib/facet/string/shuffle.rb +1 -42
- data/lib/facet/string/similarity.rb +1 -108
- data/lib/facet/string/singular.rb +1 -117
- data/lib/facet/string/slap.rb +1 -44
- data/lib/facet/string/soundex.rb +1 -102
- data/lib/facet/string/starts_with.rb +1 -24
- data/lib/facet/string/succ.rb +1 -38
- data/lib/facet/string/tab.rb +1 -2
- data/lib/facet/string/tabto.rb +1 -2
- data/lib/facet/string/to_a.rb +1 -35
- data/lib/facet/string/to_arr.rb +1 -55
- data/lib/facet/string/to_b.rb +1 -64
- data/lib/facet/string/to_const.rb +1 -39
- data/lib/facet/string/to_date.rb +1 -35
- data/lib/facet/string/to_proc.rb +1 -54
- data/lib/facet/string/to_re.rb +1 -46
- data/lib/facet/string/to_rx.rb +1 -2
- data/lib/facet/string/to_time.rb +1 -34
- data/lib/facet/string/unbracket.rb +1 -46
- data/lib/facet/string/underscore.rb +1 -18
- data/lib/facet/string/unix_crypt.rb +1 -41
- data/lib/facet/string/unpack.rb +1 -45
- data/lib/facet/string/unshift.rb +1 -42
- data/lib/facet/string/upcase.rb +1 -45
- data/lib/facet/string/uppercase.rb +1 -2
- data/lib/facet/string/whitespace.rb +1 -27
- data/lib/facet/string/word_filter.rb +1 -61
- data/lib/facet/string/word_wrap.rb +1 -90
- data/lib/facet/string/words.rb +1 -45
- data/lib/facet/string_as_array.rb +1 -16
- data/lib/facet/symbol.rb +1 -13
- data/lib/facet/symbol/camelcase.rb +1 -42
- data/lib/facet/symbol/camelize.rb +1 -33
- data/lib/facet/symbol/capitalize.rb +1 -31
- data/lib/facet/symbol/capitalized.rb +1 -33
- data/lib/facet/symbol/downcase.rb +1 -36
- data/lib/facet/symbol/not.rb +1 -40
- data/lib/facet/symbol/pad.rb +1 -43
- data/lib/facet/symbol/succ.rb +1 -42
- data/lib/facet/symbol/to_const.rb +1 -40
- data/lib/facet/symbol/to_proc.rb +1 -45
- data/lib/facet/symbol/to_str.rb +1 -39
- data/lib/facet/symbol/underscore.rb +1 -32
- data/lib/facet/symbol/upcase.rb +1 -37
- data/lib/facet/syncarray.rb +1 -0
- data/lib/facet/synchash.rb +1 -0
- data/lib/facet/system.rb +1 -0
- data/lib/facet/tagiterator.rb +1 -0
- data/lib/facet/time.rb +1 -8
- data/lib/facet/time/change.rb +1 -51
- data/lib/facet/time/elapse.rb +1 -41
- data/lib/facet/time/self/days_extrema.rb +1 -22
- data/lib/facet/time/self/stamp.rb +1 -2
- data/lib/facet/time/stamp.rb +1 -51
- data/lib/facet/time/to_date.rb +1 -37
- data/lib/facet/time/to_s.rb +1 -33
- data/lib/facet/time/to_time.rb +1 -36
- data/lib/facet/timer.rb +1 -0
- data/lib/facet/times.rb +1 -0
- data/lib/facet/tracepoint.rb +1 -0
- data/lib/facet/tuple.rb +1 -0
- data/lib/facet/typecast.rb +1 -0
- data/lib/facet/unboundmethod.rb +1 -1
- data/lib/facet/unboundmethod/name.rb +1 -8
- data/lib/facet/uninheritable.rb +1 -0
- data/lib/facet/units.rb +1 -0
- data/lib/facet/yamlstruct.rb +1 -0
- data/lib/facets.rb +77 -45
- data/lib/facets/core/array.rb +34 -0
- data/lib/facets/core/array/at_rand.rb +52 -0
- data/lib/facets/core/array/body.rb +2 -0
- data/lib/facets/core/array/delete_unless.rb +35 -0
- data/lib/facets/core/array/delete_values.rb +38 -0
- data/lib/facets/core/array/delete_values_at.rb +57 -0
- data/lib/facets/core/array/each_with_key.rb +9 -0
- data/lib/facets/core/array/first.rb +84 -0
- data/lib/facets/core/array/foot.rb +2 -0
- data/lib/facets/core/array/head.rb +80 -0
- data/lib/facets/core/array/last.rb +2 -0
- data/lib/facets/core/array/last_index.rb +35 -0
- data/lib/facets/core/array/merge.rb +40 -0
- data/lib/facets/core/array/mid.rb +50 -0
- data/lib/facets/core/array/middle.rb +45 -0
- data/lib/facets/core/array/op_fetch.rb +40 -0
- data/lib/facets/core/array/op_mod.rb +16 -0
- data/lib/facets/core/array/op_store.rb +47 -0
- data/lib/facets/core/array/pick.rb +68 -0
- data/lib/facets/core/array/pos.rb +39 -0
- data/lib/facets/core/array/pull.rb +37 -0
- data/lib/facets/core/array/rand_index.rb +30 -0
- data/lib/facets/core/array/rand_subset.rb +56 -0
- data/lib/facets/core/array/range.rb +47 -0
- data/lib/facets/core/array/rotate.rb +67 -0
- data/lib/facets/core/array/select.rb +37 -0
- data/lib/facets/core/array/shuffle.rb +66 -0
- data/lib/facets/core/array/slap.rb +37 -0
- data/lib/facets/core/array/store.rb +7 -0
- data/lib/facets/core/array/tail.rb +2 -0
- data/lib/facets/core/array/thru.rb +38 -0
- data/lib/facets/core/array/to_b.rb +31 -0
- data/lib/facets/core/array/to_h.rb +57 -0
- data/lib/facets/core/array/to_hash.rb +46 -0
- data/lib/facets/core/array/unzip.rb +20 -0
- data/lib/facets/core/binding.rb +14 -0
- data/lib/facets/core/binding/__DIR__.rb +2 -0
- data/lib/facets/core/binding/__FILE__.rb +2 -0
- data/lib/facets/core/binding/__LINE__.rb +58 -0
- data/lib/facets/core/binding/call_stack.rb +42 -0
- data/lib/facets/core/binding/called.rb +42 -0
- data/lib/facets/core/binding/caller.rb +42 -0
- data/lib/facets/core/binding/defined.rb +41 -0
- data/lib/facets/core/binding/eval.rb +42 -0
- data/lib/facets/core/binding/local_variables.rb +45 -0
- data/lib/facets/core/binding/method_name.rb +48 -0
- data/lib/facets/core/binding/op_fetch.rb +45 -0
- data/lib/facets/core/binding/op_store.rb +46 -0
- data/lib/facets/core/binding/self.rb +41 -0
- data/lib/facets/core/binding/self/of_caller.rb +122 -0
- data/lib/facets/core/class.rb +7 -0
- data/lib/facets/core/class/by_name.rb +1 -0
- data/lib/facets/core/class/descendents.rb +44 -0
- data/lib/facets/core/class/method_name.rb +33 -0
- data/lib/facets/core/class/remove_descendents.rb +46 -0
- data/lib/facets/core/class/remove_subclasses.rb +2 -0
- data/lib/facets/core/class/subclasses.rb +2 -0
- data/lib/facets/core/class/unix_path.rb +34 -0
- data/lib/facets/core/comparable.rb +5 -0
- data/lib/facets/core/comparable/at_least.rb +53 -0
- data/lib/facets/core/comparable/at_most.rb +2 -0
- data/lib/facets/core/comparable/cap.rb +2 -0
- data/lib/facets/core/comparable/clip.rb +72 -0
- data/lib/facets/core/comparable/cmp.rb +38 -0
- data/lib/facets/core/continuation.rb +1 -0
- data/lib/facets/core/continuation/self/create.rb +71 -0
- data/lib/facets/core/date.rb +0 -0
- data/lib/facets/core/date/days_in_month.rb +42 -0
- data/lib/facets/core/date/days_of_month.rb +34 -0
- data/lib/facets/core/date/stamp.rb +52 -0
- data/lib/facets/core/date/to_date.rb +36 -0
- data/lib/facets/core/date/to_s.rb +33 -0
- data/lib/facets/core/date/to_time.rb +36 -0
- data/lib/facets/core/dir.rb +4 -0
- data/lib/facets/core/dir/self/ancestor.rb +33 -0
- data/lib/facets/core/dir/self/ascend.rb +56 -0
- data/lib/facets/core/dir/self/ls_r.rb +76 -0
- data/lib/facets/core/dir/self/recurse.rb +2 -0
- data/lib/facets/core/enumerable.rb +39 -0
- data/lib/facets/core/enumerable/collect_with_counter.rb +2 -0
- data/lib/facets/core/enumerable/collect_with_index.rb +51 -0
- data/lib/facets/core/enumerable/commonality.rb +63 -0
- data/lib/facets/core/enumerable/compact_collect.rb +50 -0
- data/lib/facets/core/enumerable/compact_map.rb +2 -0
- data/lib/facets/core/enumerable/cross.rb +44 -0
- data/lib/facets/core/enumerable/each_by.rb +2 -0
- data/lib/facets/core/enumerable/each_combination.rb +59 -0
- data/lib/facets/core/enumerable/each_pair.rb +50 -0
- data/lib/facets/core/enumerable/each_permutation.rb +2 -0
- data/lib/facets/core/enumerable/each_slice.rb +131 -0
- data/lib/facets/core/enumerable/each_unique_pair.rb +66 -0
- data/lib/facets/core/enumerable/each_with_counter.rb +8 -0
- data/lib/facets/core/enumerable/elementwise.rb +2 -0
- data/lib/facets/core/enumerable/entropy.rb +52 -0
- data/lib/facets/core/enumerable/every.rb +65 -0
- data/lib/facets/core/enumerable/ew.rb +64 -0
- data/lib/facets/core/enumerable/filter_collect.rb +58 -0
- data/lib/facets/core/enumerable/filter_map.rb +2 -0
- data/lib/facets/core/enumerable/find_collisions.rb +41 -0
- data/lib/facets/core/enumerable/frequency.rb +39 -0
- data/lib/facets/core/enumerable/graph.rb +59 -0
- data/lib/facets/core/enumerable/ideal_entropy.rb +49 -0
- data/lib/facets/core/enumerable/map_with_counter.rb +2 -0
- data/lib/facets/core/enumerable/map_with_index.rb +2 -0
- data/lib/facets/core/enumerable/none.rb +56 -0
- data/lib/facets/core/enumerable/nonuniq.rb +39 -0
- data/lib/facets/core/enumerable/occur.rb +62 -0
- data/lib/facets/core/enumerable/one.rb +65 -0
- data/lib/facets/core/enumerable/op_pow.rb +38 -0
- data/lib/facets/core/enumerable/partition_by.rb +55 -0
- data/lib/facets/core/enumerable/permute.rb +135 -0
- data/lib/facets/core/enumerable/probability.rb +59 -0
- data/lib/facets/core/enumerable/project.rb +11 -0
- data/lib/facets/core/enumerable/self/combinations.rb +68 -0
- data/lib/facets/core/enumerable/self/cross.rb +79 -0
- data/lib/facets/core/enumerable/to_h.rb +50 -0
- data/lib/facets/core/enumerable/uniq_by.rb +39 -0
- data/lib/facets/core/enumerable/where.rb +12 -0
- data/lib/facets/core/file.rb +5 -0
- data/lib/facets/core/file/self/create.rb +52 -0
- data/lib/facets/core/file/self/open_as_string.rb +81 -0
- data/lib/facets/core/file/self/read_list.rb +47 -0
- data/lib/facets/core/file/self/sanitize.rb +50 -0
- data/lib/facets/core/file/self/split_all.rb +36 -0
- data/lib/facets/core/fileutils.rb +0 -0
- data/lib/facets/core/fileutils/head.rb +2 -0
- data/lib/facets/core/fileutils/safe_ln.rb +38 -0
- data/lib/facets/core/fileutils/slice.rb +152 -0
- data/lib/facets/core/fileutils/split_all.rb +29 -0
- data/lib/facets/core/fileutils/tail.rb +2 -0
- data/lib/facets/core/fileutils/wc.rb +128 -0
- data/lib/facets/core/fileutils/whereis.rb +76 -0
- data/lib/facets/core/fileutils/which.rb +117 -0
- data/lib/facets/core/float.rb +3 -0
- data/lib/facets/core/float/approx.rb +42 -0
- data/lib/facets/core/float/round_at.rb +72 -0
- data/lib/facets/core/float/round_to.rb +73 -0
- data/lib/facets/core/gem.rb +3 -0
- data/lib/facets/core/gem/self/active.rb +9 -0
- data/lib/facets/core/gem/self/gempath.rb +10 -0
- data/lib/facets/core/gem/self/gemspec.rb +10 -0
- data/lib/facets/core/hash.rb +40 -0
- data/lib/facets/core/hash/alias.rb +54 -0
- data/lib/facets/core/hash/assert_has_keys.rb +38 -0
- data/lib/facets/core/hash/assert_has_only_keys.rb +38 -0
- data/lib/facets/core/hash/at.rb +26 -0
- data/lib/facets/core/hash/collate.rb +53 -0
- data/lib/facets/core/hash/delete_unless.rb +15 -0
- data/lib/facets/core/hash/each.rb +61 -0
- data/lib/facets/core/hash/each_with_index.rb +35 -0
- data/lib/facets/core/hash/each_with_key.rb +32 -0
- data/lib/facets/core/hash/graph.rb +31 -0
- data/lib/facets/core/hash/has_keys.rb +37 -0
- data/lib/facets/core/hash/has_only_keys.rb +37 -0
- data/lib/facets/core/hash/inverse.rb +51 -0
- data/lib/facets/core/hash/join.rb +19 -0
- data/lib/facets/core/hash/keys_to_iv.rb +60 -0
- data/lib/facets/core/hash/keys_to_s.rb +80 -0
- data/lib/facets/core/hash/keys_to_sym.rb +91 -0
- data/lib/facets/core/hash/op_fetch.rb +146 -0
- data/lib/facets/core/hash/op_lshift.rb +28 -0
- data/lib/facets/core/hash/op_store.rb +2 -0
- data/lib/facets/core/hash/rand_key.rb +47 -0
- data/lib/facets/core/hash/rand_pair.rb +50 -0
- data/lib/facets/core/hash/rand_value.rb +60 -0
- data/lib/facets/core/hash/replace_each.rb +33 -0
- data/lib/facets/core/hash/self/zipnew.rb +37 -0
- data/lib/facets/core/hash/shuffle.rb +53 -0
- data/lib/facets/core/hash/slice.rb +33 -0
- data/lib/facets/core/hash/stringify_keys.rb +2 -0
- data/lib/facets/core/hash/swap.rb +36 -0
- data/lib/facets/core/hash/swapkey.rb +44 -0
- data/lib/facets/core/hash/symoblize_keys.rb +2 -0
- data/lib/facets/core/hash/to_h.rb +35 -0
- data/lib/facets/core/hash/to_ostruct.rb +40 -0
- data/lib/facets/core/hash/to_ostruct_recurse.rb +45 -0
- data/lib/facets/core/hash/traverse.rb +63 -0
- data/lib/facets/core/hash/update_each.rb +43 -0
- data/lib/facets/core/hash/update_keys.rb +31 -0
- data/lib/facets/core/hash/update_values.rb +32 -0
- data/lib/facets/core/hash/variablize_keys.rb +2 -0
- data/lib/facets/core/hash/weave.rb +88 -0
- data/lib/facets/core/inflect.rb +70 -0
- data/lib/facets/core/integer.rb +9 -0
- data/lib/facets/core/integer/even.rb +2 -0
- data/lib/facets/core/integer/fac.rb +2 -0
- data/lib/facets/core/integer/fact.rb +2 -0
- data/lib/facets/core/integer/factorial.rb +61 -0
- data/lib/facets/core/integer/multiple.rb +69 -0
- data/lib/facets/core/integer/odd.rb +2 -0
- data/lib/facets/core/integer/ordinal.rb +41 -0
- data/lib/facets/core/integer/times_collect.rb +39 -0
- data/lib/facets/core/integer/times_map.rb +2 -0
- data/lib/facets/core/kernel.rb +68 -0
- data/lib/facets/core/kernel/__DIR__.rb +11 -0
- data/lib/facets/core/kernel/__class__.rb +31 -0
- data/lib/facets/core/kernel/__meta__.rb +28 -0
- data/lib/facets/core/kernel/adhoc.rb +11 -0
- data/lib/facets/core/kernel/as.rb +87 -0
- data/lib/facets/core/kernel/assign_from.rb +82 -0
- data/lib/facets/core/kernel/assign_with.rb +75 -0
- data/lib/facets/core/kernel/autoreload.rb +124 -0
- data/lib/facets/core/kernel/autoreload_files.rb +2 -0
- data/lib/facets/core/kernel/autoreload_glob.rb +3 -0
- data/lib/facets/core/kernel/bool.rb +77 -0
- data/lib/facets/core/kernel/bug.rb +39 -0
- data/lib/facets/core/kernel/call_stack.rb +59 -0
- data/lib/facets/core/kernel/called.rb +40 -0
- data/lib/facets/core/kernel/complete.rb +6 -0
- data/lib/facets/core/kernel/constant.rb +52 -0
- data/lib/facets/core/kernel/copy.rb +48 -0
- data/lib/facets/core/kernel/deep_copy.rb +49 -0
- data/lib/facets/core/kernel/demo.rb +46 -0
- data/lib/facets/core/kernel/eigenclass.rb +17 -0
- data/lib/facets/core/kernel/false.rb +2 -0
- data/lib/facets/core/kernel/fn.rb +33 -0
- data/lib/facets/core/kernel/generate_method_name.rb +39 -0
- data/lib/facets/core/kernel/get_by_id.rb +33 -0
- data/lib/facets/core/kernel/here.rb +34 -0
- data/lib/facets/core/kernel/in.rb +35 -0
- data/lib/facets/core/kernel/instance_assign.rb +25 -0
- data/lib/facets/core/kernel/instvar.rb +13 -0
- data/lib/facets/core/kernel/is.rb +7 -0
- data/lib/facets/core/kernel/maybe.rb +41 -0
- data/lib/facets/core/kernel/me.rb +17 -0
- data/lib/facets/core/kernel/meta.rb +2 -0
- data/lib/facets/core/kernel/metaclass.rb +42 -0
- data/lib/facets/core/kernel/method.rb +76 -0
- data/lib/facets/core/kernel/method_name.rb +49 -0
- data/lib/facets/core/kernel/methods.rb +79 -0
- data/lib/facets/core/kernel/nack.rb +12 -0
- data/lib/facets/core/kernel/new.rb +40 -0
- data/lib/facets/core/kernel/object_class.rb +31 -0
- data/lib/facets/core/kernel/object_hexid.rb +35 -0
- data/lib/facets/core/kernel/op_esc.rb +37 -0
- data/lib/facets/core/kernel/own.rb +17 -0
- data/lib/facets/core/kernel/p.rb +12 -0
- data/lib/facets/core/kernel/require_all.rb +44 -0
- data/lib/facets/core/kernel/require_esc.rb +42 -0
- data/lib/facets/core/kernel/require_facet.rb +41 -0
- data/lib/facets/core/kernel/require_local.rb +25 -0
- data/lib/facets/core/kernel/resc.rb +32 -0
- data/lib/facets/core/kernel/returning.rb +49 -0
- data/lib/facets/core/kernel/send_as.rb +34 -0
- data/lib/facets/core/kernel/set_from.rb +69 -0
- data/lib/facets/core/kernel/set_with.rb +74 -0
- data/lib/facets/core/kernel/silence_warnings.rb +2 -0
- data/lib/facets/core/kernel/silently.rb +41 -0
- data/lib/facets/core/kernel/singleton.rb +47 -0
- data/lib/facets/core/kernel/superior.rb +53 -0
- data/lib/facets/core/kernel/supermethod.rb +44 -0
- data/lib/facets/core/kernel/this.rb +33 -0
- data/lib/facets/core/kernel/to_b.rb +41 -0
- data/lib/facets/core/kernel/to_bool.rb +47 -0
- data/lib/facets/core/kernel/true.rb +2 -0
- data/lib/facets/core/kernel/unuri.rb +2 -0
- data/lib/facets/core/kernel/uri.rb +38 -0
- data/lib/facets/core/kernel/val.rb +52 -0
- data/lib/facets/core/kernel/warn_with_line.rb +30 -0
- data/lib/facets/core/kernel/with_accessor.rb +94 -0
- data/lib/facets/core/kernel/with_reader.rb +2 -0
- data/lib/facets/core/kernel/with_writer.rb +2 -0
- data/lib/facets/core/logger.rb +0 -0
- data/lib/facets/core/logger/format.rb +28 -0
- data/lib/facets/core/logger/format_message.rb +1 -0
- data/lib/facets/core/matchdata.rb +3 -0
- data/lib/facets/core/matchdata/match.rb +37 -0
- data/lib/facets/core/matchdata/matchset.rb +2 -0
- data/lib/facets/core/matchdata/matchtree.rb +62 -0
- data/lib/facets/core/module.rb +40 -0
- data/lib/facets/core/module/abstract.rb +50 -0
- data/lib/facets/core/module/alias_module_function.rb +57 -0
- data/lib/facets/core/module/ancestor.rb +38 -0
- data/lib/facets/core/module/attr.rb +23 -0
- data/lib/facets/core/module/attr_setter.rb +48 -0
- data/lib/facets/core/module/attr_tester.rb +56 -0
- data/lib/facets/core/module/basename.rb +39 -0
- data/lib/facets/core/module/by_name.rb +68 -0
- data/lib/facets/core/module/cattr_accessor.rb +141 -0
- data/lib/facets/core/module/cattr_reader.rb +2 -0
- data/lib/facets/core/module/cattr_writer.rb +2 -0
- data/lib/facets/core/module/clone_removing.rb +2 -0
- data/lib/facets/core/module/clone_renaming.rb +2 -0
- data/lib/facets/core/module/clone_using.rb +87 -0
- data/lib/facets/core/module/dirname.rb +42 -0
- data/lib/facets/core/module/equate_on.rb +70 -0
- data/lib/facets/core/module/generate_instance_method_name.rb +47 -0
- data/lib/facets/core/module/include_as.rb +102 -0
- data/lib/facets/core/module/initializer.rb +65 -0
- data/lib/facets/core/module/instance_methods.rb +186 -0
- data/lib/facets/core/module/integrate.rb +51 -0
- data/lib/facets/core/module/is.rb +35 -0
- data/lib/facets/core/module/memoize.rb +95 -0
- data/lib/facets/core/module/modspace.rb +43 -0
- data/lib/facets/core/module/namespace.rb +61 -0
- data/lib/facets/core/module/nesting.rb +45 -0
- data/lib/facets/core/module/redef.rb +31 -0
- data/lib/facets/core/module/redefine_method.rb +57 -0
- data/lib/facets/core/module/redirect.rb +30 -0
- data/lib/facets/core/module/redirect_method.rb +64 -0
- data/lib/facets/core/module/remove.rb +29 -0
- data/lib/facets/core/module/rename.rb +31 -0
- data/lib/facets/core/module/rename_method.rb +38 -0
- data/lib/facets/core/module/revisal.rb +49 -0
- data/lib/facets/core/module/shadow_all.rb +17 -0
- data/lib/facets/core/module/shadow_method.rb +42 -0
- data/lib/facets/core/module/sort_on.rb +73 -0
- data/lib/facets/core/module/undef.rb +29 -0
- data/lib/facets/core/module/wrap.rb +30 -0
- data/lib/facets/core/module/wrap_method.rb +48 -0
- data/lib/facets/core/nil_as_emptiness.rb +34 -0
- data/lib/facets/core/nilclass.rb +7 -0
- data/lib/facets/core/nilclass/empty.rb +32 -0
- data/lib/facets/core/nilclass/include.rb +32 -0
- data/lib/facets/core/nilclass/length.rb +2 -0
- data/lib/facets/core/nilclass/op_fetch.rb +37 -0
- data/lib/facets/core/nilclass/size.rb +44 -0
- data/lib/facets/core/nilclass/to_f.rb +32 -0
- data/lib/facets/core/nilclass/to_h.rb +33 -0
- data/lib/facets/core/numeric.rb +5 -0
- data/lib/facets/core/numeric/ceil_multiple.rb +40 -0
- data/lib/facets/core/numeric/pred.rb +2 -0
- data/lib/facets/core/numeric/succ.rb +69 -0
- data/lib/facets/core/numeric/to_b.rb +38 -0
- data/lib/facets/core/ostruct.rb +0 -0
- data/lib/facets/core/ostruct/__merge__.rb +52 -0
- data/lib/facets/core/ostruct/__table__.rb +17 -0
- data/lib/facets/core/ostruct/__update__.rb +45 -0
- data/lib/facets/core/ostruct/op_fetch.rb +40 -0
- data/lib/facets/core/ostruct/op_store.rb +42 -0
- data/lib/facets/core/ostruct/to_h.rb +8 -0
- data/lib/facets/core/pathname.rb +2 -0
- data/lib/facets/core/pathname/ascend.rb +22 -0
- data/lib/facets/core/pathname/descend.rb +20 -0
- data/lib/facets/core/proc.rb +3 -0
- data/lib/facets/core/proc/compose.rb +62 -0
- data/lib/facets/core/proc/op_mul.rb +2 -0
- data/lib/facets/core/proc/to_method.rb +74 -0
- data/lib/facets/core/random.rb +21 -0
- data/lib/facets/core/range.rb +4 -0
- data/lib/facets/core/range/to_r.rb +32 -0
- data/lib/facets/core/range/to_range.rb +36 -0
- data/lib/facets/core/range/umbrella.rb +67 -0
- data/lib/facets/core/range/within.rb +44 -0
- data/lib/facets/core/regexp.rb +3 -0
- data/lib/facets/core/regexp/arity.rb +41 -0
- data/lib/facets/core/regexp/to_re.rb +38 -0
- data/lib/facets/core/regexp/to_regexp.rb +36 -0
- data/lib/facets/core/string.rb +92 -0
- data/lib/facets/core/string/align_center.rb +87 -0
- data/lib/facets/core/string/align_left.rb +2 -0
- data/lib/facets/core/string/align_right.rb +2 -0
- data/lib/facets/core/string/at.rb +8 -0
- data/lib/facets/core/string/at_rand.rb +65 -0
- data/lib/facets/core/string/basename.rb +48 -0
- data/lib/facets/core/string/blank.rb +36 -0
- data/lib/facets/core/string/bracket.rb +70 -0
- data/lib/facets/core/string/brief.rb +33 -0
- data/lib/facets/core/string/bytes.rb +19 -0
- data/lib/facets/core/string/camelcase.rb +58 -0
- data/lib/facets/core/string/camelize.rb +35 -0
- data/lib/facets/core/string/capitalized.rb +38 -0
- data/lib/facets/core/string/chars.rb +34 -0
- data/lib/facets/core/string/cmp.rb +43 -0
- data/lib/facets/core/string/demodulize.rb +40 -0
- data/lib/facets/core/string/dequote.rb +29 -0
- data/lib/facets/core/string/downcase.rb +37 -0
- data/lib/facets/core/string/dresner.rb +49 -0
- data/lib/facets/core/string/each_char.rb +35 -0
- data/lib/facets/core/string/each_word.rb +50 -0
- data/lib/facets/core/string/ends_with.rb +2 -0
- data/lib/facets/core/string/first.rb +94 -0
- data/lib/facets/core/string/first_char.rb +20 -0
- data/lib/facets/core/string/fold.rb +67 -0
- data/lib/facets/core/string/format.rb +17 -0
- data/lib/facets/core/string/frequency.rb +39 -0
- data/lib/facets/core/string/humanize.rb +31 -0
- data/lib/facets/core/string/indent.rb +68 -0
- data/lib/facets/core/string/index_all.rb +40 -0
- data/lib/facets/core/string/last.rb +94 -0
- data/lib/facets/core/string/last_char.rb +22 -0
- data/lib/facets/core/string/line_wrap.rb +77 -0
- data/lib/facets/core/string/lines.rb +33 -0
- data/lib/facets/core/string/lowercase.rb +32 -0
- data/lib/facets/core/string/margin.rb +138 -0
- data/lib/facets/core/string/methodize.rb +44 -0
- data/lib/facets/core/string/modulize.rb +44 -0
- data/lib/facets/core/string/mscan.rb +42 -0
- data/lib/facets/core/string/natcmp.rb +108 -0
- data/lib/facets/core/string/nchar.rb +45 -0
- data/lib/facets/core/string/ordinal.rb +16 -0
- data/lib/facets/core/string/pathize.rb +46 -0
- data/lib/facets/core/string/plural.rb +2 -0
- data/lib/facets/core/string/pop.rb +54 -0
- data/lib/facets/core/string/probability.rb +34 -0
- data/lib/facets/core/string/pull.rb +17 -0
- data/lib/facets/core/string/push.rb +44 -0
- data/lib/facets/core/string/quote.rb +68 -0
- data/lib/facets/core/string/rand_byte.rb +55 -0
- data/lib/facets/core/string/rand_index.rb +29 -0
- data/lib/facets/core/string/range.rb +37 -0
- data/lib/facets/core/string/range_all.rb +48 -0
- data/lib/facets/core/string/range_of_line.rb +42 -0
- data/lib/facets/core/string/regesc.rb +32 -0
- data/lib/facets/core/string/self/format.rb +17 -0
- data/lib/facets/core/string/self/interpolate.rb +31 -0
- data/lib/facets/core/string/self/patterns.rb +51 -0
- data/lib/facets/core/string/self/rand_letter.rb +34 -0
- data/lib/facets/core/string/self/random.rb +37 -0
- data/lib/facets/core/string/shatter.rb +45 -0
- data/lib/facets/core/string/shell_escape.rb +11 -0
- data/lib/facets/core/string/shift.rb +42 -0
- data/lib/facets/core/string/shuffle.rb +42 -0
- data/lib/facets/core/string/similarity.rb +108 -0
- data/lib/facets/core/string/singular.rb +117 -0
- data/lib/facets/core/string/slap.rb +44 -0
- data/lib/facets/core/string/soundex.rb +102 -0
- data/lib/facets/core/string/starts_with.rb +24 -0
- data/lib/facets/core/string/succ.rb +38 -0
- data/lib/facets/core/string/tab.rb +2 -0
- data/lib/facets/core/string/tabto.rb +2 -0
- data/lib/facets/core/string/to_a.rb +35 -0
- data/lib/facets/core/string/to_arr.rb +55 -0
- data/lib/facets/core/string/to_b.rb +64 -0
- data/lib/facets/core/string/to_const.rb +39 -0
- data/lib/facets/core/string/to_date.rb +35 -0
- data/lib/facets/core/string/to_proc.rb +54 -0
- data/lib/facets/core/string/to_re.rb +46 -0
- data/lib/facets/core/string/to_rx.rb +2 -0
- data/lib/facets/core/string/to_time.rb +34 -0
- data/lib/facets/core/string/unbracket.rb +46 -0
- data/lib/facets/core/string/underscore.rb +18 -0
- data/lib/facets/core/string/unix_crypt.rb +41 -0
- data/lib/facets/core/string/unpack.rb +45 -0
- data/lib/facets/core/string/unshift.rb +42 -0
- data/lib/facets/core/string/upcase.rb +45 -0
- data/lib/facets/core/string/uppercase.rb +2 -0
- data/lib/facets/core/string/whitespace.rb +27 -0
- data/lib/facets/core/string/word_filter.rb +61 -0
- data/lib/facets/core/string/word_wrap.rb +90 -0
- data/lib/facets/core/string/words.rb +45 -0
- data/lib/facets/core/string_as_array.rb +16 -0
- data/lib/facets/core/symbol.rb +13 -0
- data/lib/facets/core/symbol/camelcase.rb +42 -0
- data/lib/facets/core/symbol/camelize.rb +33 -0
- data/lib/facets/core/symbol/capitalize.rb +31 -0
- data/lib/facets/core/symbol/capitalized.rb +33 -0
- data/lib/facets/core/symbol/downcase.rb +36 -0
- data/lib/facets/core/symbol/not.rb +40 -0
- data/lib/facets/core/symbol/pad.rb +43 -0
- data/lib/facets/core/symbol/succ.rb +42 -0
- data/lib/facets/core/symbol/to_const.rb +40 -0
- data/lib/facets/core/symbol/to_proc.rb +45 -0
- data/lib/facets/core/symbol/to_str.rb +39 -0
- data/lib/facets/core/symbol/underscore.rb +32 -0
- data/lib/facets/core/symbol/upcase.rb +37 -0
- data/lib/facets/core/time.rb +8 -0
- data/lib/facets/core/time/change.rb +51 -0
- data/lib/facets/core/time/elapse.rb +41 -0
- data/lib/facets/core/time/self/days_extrema.rb +22 -0
- data/lib/facets/core/time/self/stamp.rb +2 -0
- data/lib/facets/core/time/stamp.rb +51 -0
- data/lib/facets/core/time/to_date.rb +37 -0
- data/lib/facets/core/time/to_s.rb +33 -0
- data/lib/facets/core/time/to_time.rb +36 -0
- data/lib/facets/core/unboundmethod.rb +1 -0
- data/lib/facets/core/unboundmethod/name.rb +8 -0
- data/lib/facets/more/annotation.rb +580 -0
- data/lib/facets/more/ansicode.rb +311 -0
- data/lib/facets/more/aspects.rb +230 -0
- data/lib/facets/more/association.rb +156 -0
- data/lib/facets/more/basicobject.rb +135 -0
- data/lib/facets/more/bbcode.rb +388 -0
- data/lib/facets/more/binaryreader.rb +246 -0
- data/lib/facets/more/bitmask.rb +112 -0
- data/lib/facets/more/blankslate.rb +3 -0
- data/lib/facets/more/bytes.rb +212 -0
- data/lib/facets/more/classinherit.rb +216 -0
- data/lib/facets/more/classmethods.rb +219 -0
- data/lib/facets/more/cloneable.rb +55 -0
- data/lib/facets/more/consoleapp.rb +123 -0
- data/lib/facets/more/coroutine.rb +172 -0
- data/lib/facets/more/crypt.rb +180 -0
- data/lib/facets/more/dictionary.rb +436 -0
- data/lib/facets/more/downloader.rb +272 -0
- data/lib/facets/more/enumerablepass.rb +285 -0
- data/lib/facets/more/expirable.rb +87 -0
- data/lib/facets/more/filelist.rb +486 -0
- data/lib/facets/more/floatstring.rb +179 -0
- data/lib/facets/more/functor.rb +105 -0
- data/lib/facets/more/heap.rb +226 -0
- data/lib/facets/more/inheritor.rb +239 -0
- data/lib/facets/more/interval.rb +424 -0
- data/lib/facets/more/ioredirect.rb +130 -0
- data/lib/facets/more/lisp.rb +387 -0
- data/lib/facets/more/lisp_format.rb +1843 -0
- data/lib/facets/more/lrucache.rb +183 -0
- data/lib/facets/more/mathconstants.rb +320 -0
- data/lib/facets/more/methodprobe.rb +215 -0
- data/lib/facets/more/mock.rb +233 -0
- data/lib/facets/more/multipliers.rb +192 -0
- data/lib/facets/more/multiton.rb +359 -0
- data/lib/facets/more/nackclass.rb +162 -0
- data/lib/facets/more/nilcomparable.rb +133 -0
- data/lib/facets/more/nullclass.rb +68 -0
- data/lib/facets/more/one.rb +117 -0
- data/lib/facets/more/openobject.rb +220 -0
- data/lib/facets/more/orderedhash.rb +3 -0
- data/lib/facets/more/ormsupport.rb +235 -0
- data/lib/facets/more/overload.rb +110 -0
- data/lib/facets/more/paramix.rb +243 -0
- data/lib/facets/more/pathlist.rb +105 -0
- data/lib/facets/more/pool.rb +98 -0
- data/lib/facets/more/preinitialize.rb +152 -0
- data/lib/facets/more/progressbar.rb +227 -0
- data/lib/facets/more/promoteself.rb +104 -0
- data/lib/facets/more/quaternion.rb +527 -0
- data/lib/facets/more/reference.rb +83 -0
- data/lib/facets/more/rtals.rb +14 -0
- data/lib/facets/more/semaphore.rb +103 -0
- data/lib/facets/more/snapshot.rb +190 -0
- data/lib/facets/more/stateparser.rb +579 -0
- data/lib/facets/more/statichash.rb +87 -0
- data/lib/facets/more/syncarray.rb +144 -0
- data/lib/facets/more/synchash.rb +173 -0
- data/lib/facets/more/system.rb +169 -0
- data/lib/facets/more/tagiterator.rb +387 -0
- data/lib/facets/more/timer.rb +307 -0
- data/lib/facets/more/times.rb +327 -0
- data/lib/facets/more/tracepoint.rb +183 -0
- data/lib/facets/more/tuple.rb +170 -0
- data/lib/facets/more/typecast.rb +280 -0
- data/lib/facets/more/uninheritable.rb +90 -0
- data/lib/facets/more/units.rb +938 -0
- data/lib/facets/more/yamlstruct.rb +90 -0
- metadata +680 -39
- data/data/facets/methods.yaml +0 -446
@@ -0,0 +1,1843 @@
|
|
1
|
+
#:title: Lisp Format
|
2
|
+
#--
|
3
|
+
# Lisp Format
|
4
|
+
# v 0.3
|
5
|
+
#
|
6
|
+
# Copyright (C) 2003 Nikolai Weibull <source@pcppopper.org>.
|
7
|
+
#
|
8
|
+
# This library is free software; you can redistribute it and/or
|
9
|
+
# modify it under the terms of the GNU Lesser General Public
|
10
|
+
# License as published by the Free Software Foundation; either
|
11
|
+
# version 2.1 of the License, or (at your option) any later version.
|
12
|
+
#
|
13
|
+
# This library is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
16
|
+
# Lesser General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU Lesser General Public
|
19
|
+
# License along with this library; if not, write to the Free Software
|
20
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
21
|
+
#
|
22
|
+
# ==========================================================================
|
23
|
+
# Revision History ::
|
24
|
+
# --------------------------------------------------------------------------
|
25
|
+
# 2004-11-16 0.3 TO * Ported en-masse as a "sub-space" of Lisp.
|
26
|
+
# 2003-12-08 0.2 NW * Releasing version 0.2.
|
27
|
+
# ==========================================================================
|
28
|
+
# To Do ::
|
29
|
+
# * the floating point functions are rather horendous
|
30
|
+
# ==========================================================================
|
31
|
+
#++
|
32
|
+
|
33
|
+
# = Description
|
34
|
+
#
|
35
|
+
# "So what is *ruby-lisp*?", you ask. Well, it is a module for implementing nice
|
36
|
+
# Lisp features for use in Ruby. Currently the only sub-module that exists is
|
37
|
+
# Lisp::Format, which implements Lisp's (format) function and its formatting
|
38
|
+
# language. For people not familiar with this language, it is a very expressive
|
39
|
+
# string formatting language, much like sprintf()'s, but much more powerful. It
|
40
|
+
# allows for iteration, case conversion, conditionals, and much more. If you
|
41
|
+
# have ever felt stupid while creating a string iteratively, to print an array or
|
42
|
+
# some such, this is definitely for you!
|
43
|
+
#
|
44
|
+
# This module contains various Lisp facilities that are of general usefulness.
|
45
|
+
# Lisp's rich string formatting language is implemented in the Format module.
|
46
|
+
# More modules may be added later.
|
47
|
+
#
|
48
|
+
# This has been (very simply) integrated into the namespace of Lsip from lisp.rb.
|
49
|
+
#
|
50
|
+
# == Author(s)
|
51
|
+
#
|
52
|
+
# * Nikolai Weibull <source@pcppopper.org>
|
53
|
+
#
|
54
|
+
# == More Information
|
55
|
+
#
|
56
|
+
# The project website for ruby-lisp is currently located at
|
57
|
+
# http://ned.rubyforge.org/.
|
58
|
+
#
|
59
|
+
|
60
|
+
#--
|
61
|
+
# This module contains various Lisp facilities that are of general usefulness.
|
62
|
+
# Lisp's rich string formatting language is implemented in the Format module.
|
63
|
+
# More modules may be added later.
|
64
|
+
#
|
65
|
+
# TODO: the floating point functions are rather horendous.
|
66
|
+
#++
|
67
|
+
|
68
|
+
module Lisp
|
69
|
+
|
70
|
+
# This module implements the Common Lisp (format) function and it's language.
|
71
|
+
module Format
|
72
|
+
|
73
|
+
# An error, positioned somewhere in the input format. This is used to be
|
74
|
+
# able to show the user exactly where something failed in the input format
|
75
|
+
# string.
|
76
|
+
module Positioned
|
77
|
+
# Create at a given position.
|
78
|
+
def initialize(pos = -1)
|
79
|
+
@pos = pos
|
80
|
+
end
|
81
|
+
|
82
|
+
# The position at which the error occured.
|
83
|
+
attr :pos, true
|
84
|
+
end
|
85
|
+
|
86
|
+
# An argument was of the wrong type, or there aren't enough arguments.
|
87
|
+
class ArgumentError < ArgumentError; include Positioned; end
|
88
|
+
|
89
|
+
# An index was not valid. Used for argument jumping errors.
|
90
|
+
class IndexError < IndexError; include Positioned; end
|
91
|
+
|
92
|
+
# A parameter was wrong in some sense.
|
93
|
+
class ParameterError < ArgumentError; include Positioned; end
|
94
|
+
|
95
|
+
# The format string contained a syntax error.
|
96
|
+
class SyntaxError < SyntaxError; include Positioned; end
|
97
|
+
|
98
|
+
# The format string was ended before a parameter could be read.
|
99
|
+
class MissingParameterError < SyntaxError; end
|
100
|
+
|
101
|
+
# The format string was ended before a parameter could be completed.
|
102
|
+
class IncompleteParameterError < SyntaxError; end
|
103
|
+
|
104
|
+
# The format string was malformed somehow.
|
105
|
+
class MalformedError < SyntaxError; end
|
106
|
+
|
107
|
+
# A modifier was wrongly given, or there were too many of the same.
|
108
|
+
class ModifierError < SyntaxError; end
|
109
|
+
|
110
|
+
# Represents output for a State object.
|
111
|
+
class Output
|
112
|
+
# Create a new Output object.
|
113
|
+
def initialize(str = '', col = 0)
|
114
|
+
@output, @col = str, col
|
115
|
+
end
|
116
|
+
|
117
|
+
# Add +str+ to the output.
|
118
|
+
def <<(str)
|
119
|
+
if str.is_a? Fixnum
|
120
|
+
@output << str.chr
|
121
|
+
# How should tabs be handled here? They should perhaps be
|
122
|
+
# interpreted as eight (8) characters wide? This of course depends
|
123
|
+
# on where @col is already at (8 - @col % 8).
|
124
|
+
@col = str == ?\n ? 0 : @col + 1
|
125
|
+
else
|
126
|
+
@output << str
|
127
|
+
@col += str.length - (str.rindex(?\n) or 0)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Convert this object to its string representation, which is the output
|
132
|
+
# gathered so far.
|
133
|
+
# TODO: this is rather silly
|
134
|
+
def to_s
|
135
|
+
@output
|
136
|
+
end
|
137
|
+
|
138
|
+
# The current output column.
|
139
|
+
attr :col, true
|
140
|
+
end
|
141
|
+
|
142
|
+
# This class represents the state of a given Formatter. It keeps track of
|
143
|
+
# output gathered and arguments left to be processed.
|
144
|
+
class State
|
145
|
+
# Create a state from arguments and a destination output
|
146
|
+
def initialize(args, output)
|
147
|
+
@args = args
|
148
|
+
@arg_pos = 0
|
149
|
+
@outputs = [output]
|
150
|
+
@case_conv = nil
|
151
|
+
end
|
152
|
+
|
153
|
+
# Push a new Output buffer to collect output in.
|
154
|
+
def push_output
|
155
|
+
@outputs << Output.new('', @outputs.last.col)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Pop and return the latest output buffer.
|
159
|
+
def pop_output
|
160
|
+
@outputs.pop
|
161
|
+
end
|
162
|
+
|
163
|
+
# Delegates output to the top-most output buffer.
|
164
|
+
def output(str)
|
165
|
+
@outputs.last << str
|
166
|
+
end
|
167
|
+
|
168
|
+
# Retrieve the current output column.
|
169
|
+
def col
|
170
|
+
@outputs.last.col
|
171
|
+
end
|
172
|
+
|
173
|
+
# Retrieve the latest output buffer.
|
174
|
+
def latest_output
|
175
|
+
@outputs.last
|
176
|
+
end
|
177
|
+
|
178
|
+
# Move +n+ steps forward or backward depending on sign amongst the
|
179
|
+
# arguments. Movement is relative or absolute depending on the boolean
|
180
|
+
# value of +relative+.
|
181
|
+
def args_move(n = 1, relative = true)
|
182
|
+
@arg_pos = relative ? @arg_pos + n : n
|
183
|
+
raise IndexError.new,
|
184
|
+
'too few arguments' if @arg_pos > @args.size
|
185
|
+
raise IndexError.new,
|
186
|
+
'cannot move past first argument' if @arg_pos < 0
|
187
|
+
end
|
188
|
+
|
189
|
+
# Get the current argument and move forward one argument.
|
190
|
+
def next_arg
|
191
|
+
args_move(1, true)
|
192
|
+
@args[@arg_pos - 1]
|
193
|
+
end
|
194
|
+
|
195
|
+
# Get the previously returned argument, without moving.
|
196
|
+
def previous_arg
|
197
|
+
args_move(-1, relative)
|
198
|
+
next_arg
|
199
|
+
end
|
200
|
+
|
201
|
+
# Push back the previously returned argument.
|
202
|
+
def push_back_arg
|
203
|
+
args_move(-1, true)
|
204
|
+
end
|
205
|
+
|
206
|
+
# Get the number of arguments left to process
|
207
|
+
def args_left
|
208
|
+
@args.size - @arg_pos
|
209
|
+
end
|
210
|
+
|
211
|
+
attr :case_conv, true
|
212
|
+
end
|
213
|
+
|
214
|
+
# Given a format string, this class lexes it and returns directives it
|
215
|
+
# finds. This includes gathering parameters and modifiers for the coming
|
216
|
+
# directives. The necessary information to create a directive is gathered
|
217
|
+
# and then passed to Directives::Factory#build. Error checking
|
218
|
+
# is performed, so that incomplete parameters are caught and malformed
|
219
|
+
# modifiers are supressed.
|
220
|
+
class Lexer
|
221
|
+
@@errorstates = {
|
222
|
+
:START => [MissingParameterError,
|
223
|
+
'format string ended before parameter was found'],
|
224
|
+
:CHAR => [IncompleteParameterError,
|
225
|
+
'format string ended before character parameter could be read'],
|
226
|
+
:INTEGER => [IncompleteParameterError,
|
227
|
+
'format string ended before integer parameter could be read'],
|
228
|
+
}
|
229
|
+
|
230
|
+
# Create a new Lexer using the given format string +format+.
|
231
|
+
def initialize(format)
|
232
|
+
@format = format
|
233
|
+
@pos = 0
|
234
|
+
end
|
235
|
+
|
236
|
+
# Read the next token, given the previous one in +previous+, and return
|
237
|
+
# it. This may either be a 'real' directive created by
|
238
|
+
# Directives::Factory#build, or a Literal created in-line. If no more
|
239
|
+
# tokens remain, +nil+ is returned.
|
240
|
+
def next_token(previous)
|
241
|
+
if have_more_input
|
242
|
+
ch = next_char
|
243
|
+
if ch == ?~
|
244
|
+
return Directives::Factory.build(params, modifiers, directive,
|
245
|
+
previous, @pos)
|
246
|
+
else
|
247
|
+
literal = Directives::Literal.new(ch.chr)
|
248
|
+
while have_more_input and (ch = peek_char) != ?~
|
249
|
+
literal << next_char.chr
|
250
|
+
end
|
251
|
+
literal << ch.chr if not have_more_input and ch == ?~
|
252
|
+
return [literal, 0]
|
253
|
+
end
|
254
|
+
else
|
255
|
+
return nil
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
private
|
260
|
+
|
261
|
+
# Returns +true+ if more input exists.
|
262
|
+
def have_more_input
|
263
|
+
@pos < @format.length
|
264
|
+
end
|
265
|
+
|
266
|
+
# Reads next character in input.
|
267
|
+
def next_char
|
268
|
+
@pos += 1
|
269
|
+
@format[@pos - 1]
|
270
|
+
end
|
271
|
+
|
272
|
+
# View the next character in input.
|
273
|
+
def peek_char
|
274
|
+
@format[@pos]
|
275
|
+
end
|
276
|
+
|
277
|
+
# Unread previously read character in input.
|
278
|
+
def unget_char
|
279
|
+
@pos -= 1
|
280
|
+
end
|
281
|
+
|
282
|
+
# Read parameters to the coming directive. Raises various errors
|
283
|
+
# sub-classed from PositionedError when given incomplete
|
284
|
+
# parameters, e.g. when it runs out of input.
|
285
|
+
def params
|
286
|
+
params = []
|
287
|
+
sign = 1
|
288
|
+
value = 0
|
289
|
+
state = :START
|
290
|
+
while have_more_input
|
291
|
+
ch = next_char
|
292
|
+
case state
|
293
|
+
when :START
|
294
|
+
case ch
|
295
|
+
when ?'
|
296
|
+
state = :CHAR
|
297
|
+
when ?V, ?v
|
298
|
+
params << Parameters::Argument.new(@pos)
|
299
|
+
state = :DONE
|
300
|
+
when ?#
|
301
|
+
params << Parameters::ArgumentCount.new(@pos)
|
302
|
+
state = :DONE
|
303
|
+
when ?,
|
304
|
+
params << Parameters::Default.new(@pos)
|
305
|
+
state = :START
|
306
|
+
when ?+, ?-, ?0, ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9
|
307
|
+
sign = (ch == ?-) ? -1 : 1
|
308
|
+
value = (ch == ?+ or ch == ?-) ? 0 : (ch - ?0)
|
309
|
+
state = :INTEGER
|
310
|
+
else
|
311
|
+
unget_char
|
312
|
+
state = :DONE
|
313
|
+
end
|
314
|
+
when :INTEGER
|
315
|
+
if (?0..?9).to_a.include? ch
|
316
|
+
value = value * 10 + (ch - ?0)
|
317
|
+
else
|
318
|
+
unget_char
|
319
|
+
value *= sign
|
320
|
+
params << Parameters::Integer.new(@pos, value)
|
321
|
+
state = :DONE
|
322
|
+
end
|
323
|
+
when :CHAR
|
324
|
+
params << Parameters::Character.new(@pos, ch)
|
325
|
+
state = :DONE
|
326
|
+
when :DONE
|
327
|
+
if ch == ?,
|
328
|
+
state = :START
|
329
|
+
else
|
330
|
+
unget_char
|
331
|
+
break
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
unless state == :DONE
|
336
|
+
raise @@errorstates[state][0].new(@pos), @@errorstates[state][1]
|
337
|
+
end
|
338
|
+
return params
|
339
|
+
end
|
340
|
+
|
341
|
+
# Read modifiers to the coming directive. Raises ModifierError if
|
342
|
+
# a specific modifier is given more than once.
|
343
|
+
def modifiers
|
344
|
+
modifiers = []
|
345
|
+
while have_more_input
|
346
|
+
ch = next_char
|
347
|
+
if ch == ?: or ch == ?@
|
348
|
+
unless modifiers.include? ch
|
349
|
+
modifiers << ch
|
350
|
+
else
|
351
|
+
raise ModifierError.new(@pos), "duplicate #{ch.chr} modifier"
|
352
|
+
end
|
353
|
+
else
|
354
|
+
unget_char
|
355
|
+
break
|
356
|
+
end
|
357
|
+
end
|
358
|
+
return modifiers
|
359
|
+
end
|
360
|
+
|
361
|
+
# Reads the directive. Raises MalformedFormatError if no input
|
362
|
+
# remains to read the directive from.
|
363
|
+
def directive
|
364
|
+
unless have_more_input
|
365
|
+
raise MalformedFormatError.new(@pos),
|
366
|
+
'format string ended before directive was found'
|
367
|
+
end
|
368
|
+
next_char
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
# Given a lexer, parses the tokens it constructs.
|
373
|
+
# It works, quite simply, by maintaining a stack of nesting levels and
|
374
|
+
# directives/tokens are added to the current stack level. When a directive
|
375
|
+
# removes a level of nesting the previous level's last directive gets
|
376
|
+
# connected, using Directive#connect.
|
377
|
+
class Parser
|
378
|
+
# Create a Parser, given a Lexer, +lexer+.
|
379
|
+
def initialize(lexer)
|
380
|
+
@lexer = lexer
|
381
|
+
end
|
382
|
+
|
383
|
+
# Do the actual parsing of the tokens. Returns a list of the
|
384
|
+
# top-level tokens to run.
|
385
|
+
def parse
|
386
|
+
stacks = [[]]
|
387
|
+
level = 0
|
388
|
+
until (token = @lexer.next_token(stacks[level>0?level-1:0].last)).nil?
|
389
|
+
directive = token[0]
|
390
|
+
nesting = token[1]
|
391
|
+
ntop = stacks[level].last.nil? ?
|
392
|
+
directive : stacks[level].last.join(directive)
|
393
|
+
stacks[level] << directive
|
394
|
+
if nesting > 0
|
395
|
+
stacks.push []
|
396
|
+
level += 1
|
397
|
+
elsif nesting < 0
|
398
|
+
directives = stacks.pop
|
399
|
+
level -= 1
|
400
|
+
stacks[level].last.connect directives
|
401
|
+
end
|
402
|
+
end
|
403
|
+
if stacks.size > 1
|
404
|
+
raise SyntaxError.new(stacks[-2].last.pos), 'unterminated directive'
|
405
|
+
end
|
406
|
+
return stacks[0]
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
# Engine for the format Lexer and Parser. Given an input format string and
|
411
|
+
# an initial State, it lets the Parser create the directives and then
|
412
|
+
# simply iterates over them, Directive#execute:ing them each.
|
413
|
+
class Formatter
|
414
|
+
# Create a Formatter from a String +format+ and a State +state+.
|
415
|
+
def initialize(format, state)
|
416
|
+
@parser, @state = Parser.new(Lexer.new(format)), state
|
417
|
+
end
|
418
|
+
|
419
|
+
# Parse and run the result.
|
420
|
+
def run
|
421
|
+
Format.execute_directives(@state, @parser.parse)
|
422
|
+
return @state.latest_output.to_s
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
# This module includes format parameter representation classes. These are
|
427
|
+
# passed to directives when they are created.
|
428
|
+
module Parameters
|
429
|
+
# Base class from which the sub-classes get their behavior. Every
|
430
|
+
# parameter should sub-class from this class.
|
431
|
+
class Parameter
|
432
|
+
# Create a parameter, found at +pos+ in the input format, and with
|
433
|
+
# +value+ as its value - if it has one.
|
434
|
+
def initialize(pos, value = nil)
|
435
|
+
@pos, @value = pos, value
|
436
|
+
end
|
437
|
+
|
438
|
+
# Retrieve this parameters value in the given State, using +default+ if
|
439
|
+
# it is not defined.
|
440
|
+
def value(state, default)
|
441
|
+
@value or default
|
442
|
+
end
|
443
|
+
|
444
|
+
# Position in the input format that this parameter was found.
|
445
|
+
attr :pos
|
446
|
+
end
|
447
|
+
|
448
|
+
# Represents the +V+ and +v+ parameters, which retrieve their value from
|
449
|
+
# the current argument.
|
450
|
+
class Argument < Parameter
|
451
|
+
# Retrieve this parameters value by getting the value of the current
|
452
|
+
# arguments integral value.
|
453
|
+
def value(state, default)
|
454
|
+
begin
|
455
|
+
arg = state.next_arg
|
456
|
+
rescue => e
|
457
|
+
e.pos = @pos if e.respond_to?(:pos) and e.pos == -1
|
458
|
+
raise
|
459
|
+
end
|
460
|
+
if arg.nil?
|
461
|
+
default
|
462
|
+
elsif arg.respond_to? :to_i
|
463
|
+
arg.to_i
|
464
|
+
else
|
465
|
+
raise ArgumentError.new(@pos),
|
466
|
+
'argument not a number or a number string'
|
467
|
+
end
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
# Represents the <tt>#</tt> parameter, which retrieves the number of
|
472
|
+
# arguments left to process.
|
473
|
+
class ArgumentCount < Parameter
|
474
|
+
# Retrieve this parameters value by getting the number of arguments
|
475
|
+
# left to process.
|
476
|
+
def value(state, default)
|
477
|
+
state.args_left
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
# Parameter used when the parameter was not specified, so use its default
|
482
|
+
# value.
|
483
|
+
class Default < Parameter; end
|
484
|
+
|
485
|
+
# Represents integral parameters, specified directly in the input format.
|
486
|
+
class Integer < Parameter; end
|
487
|
+
|
488
|
+
# Represents character parameters, specified directly in the input
|
489
|
+
# format.
|
490
|
+
class Character < Parameter; end
|
491
|
+
end
|
492
|
+
|
493
|
+
# This module contains all the formatting directives that are defined in
|
494
|
+
# the Lisp formatting embedded language. The base class for all directives
|
495
|
+
# is aptly named Directive, and all directive classes should sub-class from
|
496
|
+
# it.
|
497
|
+
module Directives
|
498
|
+
# An unknown directive was found in the format string.
|
499
|
+
class UnknownDirectiveError < SyntaxError; end
|
500
|
+
|
501
|
+
# Represents a string literal in the input format. This is used for
|
502
|
+
# combining running lengths of characters with a single pseudo-directive.
|
503
|
+
class Literal < String
|
504
|
+
# Outputs the string literal this instance represents to the output
|
505
|
+
# stream.
|
506
|
+
def execute(state)
|
507
|
+
state.output self
|
508
|
+
end
|
509
|
+
|
510
|
+
# If the following directive is also a Literal, its contents is simply
|
511
|
+
# added to this ones, and returns self. Otherwise the other directive
|
512
|
+
# is returned.
|
513
|
+
def join(other)
|
514
|
+
other.is_a?(Literal) ? self << other : other
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
# Base class for formatting directives. This class makes it easy for
|
519
|
+
# sub-classes to access the parameters and modifiers that were given to
|
520
|
+
# it when created.
|
521
|
+
class Directive
|
522
|
+
# Given a set of parameters, modifiers, an owning directive if
|
523
|
+
# available, and a position in the output string, create a new
|
524
|
+
# Directive.
|
525
|
+
def initialize(params, modifiers, top, pos)
|
526
|
+
@params, @modifiers, @pos = params, modifiers, pos
|
527
|
+
end
|
528
|
+
|
529
|
+
# This method should be overridden in sub-classes. It gets called when
|
530
|
+
# the directive is to be executed. It does nothing by default.
|
531
|
+
def execute(state); end
|
532
|
+
|
533
|
+
# Join this directive with the following one, given in +other+. The
|
534
|
+
# default is to simply return +other+. The only known use for this is
|
535
|
+
# in SkipWhitespace, where some processing of other is done if it is a
|
536
|
+
# Literal.
|
537
|
+
def join(other)
|
538
|
+
other
|
539
|
+
end
|
540
|
+
|
541
|
+
# The position at which this directive occurs in the input string.
|
542
|
+
attr :pos
|
543
|
+
|
544
|
+
protected
|
545
|
+
|
546
|
+
# Read the +param+:th parameter in the Lisp::Format::State +state+,
|
547
|
+
# using +default+ as a default value if the parameter was not given.
|
548
|
+
def param(param, state, default)
|
549
|
+
param < @params.size ? @params[param].value(state, default) : default
|
550
|
+
end
|
551
|
+
|
552
|
+
# Check if the colon (<tt>:</tt>) modifier was given.
|
553
|
+
def colon_mod?
|
554
|
+
modifier? ?:
|
555
|
+
end
|
556
|
+
|
557
|
+
# Check if the at (<tt>@</tt>) modifier was given.
|
558
|
+
def at_mod?
|
559
|
+
modifier? ?@
|
560
|
+
end
|
561
|
+
|
562
|
+
# Check if the given +modifier+ was given. This method should not
|
563
|
+
# generally be called, as #colon_mod? and #at_mod? are easier and
|
564
|
+
# better to use.
|
565
|
+
def modifier?(modifier)
|
566
|
+
@modifiers.include? modifier
|
567
|
+
end
|
568
|
+
|
569
|
+
def arg_error(message)
|
570
|
+
raise ArgumentError.new(@pos), message
|
571
|
+
end
|
572
|
+
|
573
|
+
def param_error(pnum, message)
|
574
|
+
raise ParameterError.new(@params[pnum].pos), message
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
# Super-class for 'printing' directives, namely ~A (Ascii) and ~S
|
579
|
+
# (SExpression). These directives print, in some sense, their argument
|
580
|
+
# in a Ruby friendly manner. This means that their argument is either
|
581
|
+
# converted to a string using Object#to_s or Object#inspect.
|
582
|
+
class Print < Directive
|
583
|
+
# All parameters except +inspect+ are simply passed on to
|
584
|
+
# Directive#initialize. If +inspect+ is true, string arguments are
|
585
|
+
# inspected as well as all other objects.
|
586
|
+
def initialize(params, modifiers, top, pos, inspect = false)
|
587
|
+
super params, modifiers, top, pos
|
588
|
+
@inspect = inspect
|
589
|
+
end
|
590
|
+
|
591
|
+
# Output the given argument as it generally prints in Ruby. The full
|
592
|
+
# form is:
|
593
|
+
# ~mincol,colinc,minpad,padchar:@[AS]
|
594
|
+
# with the following interpretations
|
595
|
+
# [+mincol+ (0)]
|
596
|
+
# minimum number of columns to output,
|
597
|
+
# [+colinc+ (1)]
|
598
|
+
# number of columns to increase by, until +mincol+ is reached,
|
599
|
+
# [+minpad+ (0)]
|
600
|
+
# minimum amount of padding to add (added before +mincol+ is
|
601
|
+
# checked),
|
602
|
+
# [+padchar+ (?\s)]
|
603
|
+
# character to pad with,
|
604
|
+
# [:]
|
605
|
+
# +nil+ is output as +nil+ (In Lisp, this outputs +nil+ as
|
606
|
+
# <tt>()</tt>, which isn't generally useful in Ruby. TODO: come up
|
607
|
+
# with better use for this modifier),
|
608
|
+
# [@]
|
609
|
+
# padding is done on the right.
|
610
|
+
def execute(state)
|
611
|
+
padmethod = at_mod? ? :rjust : :ljust
|
612
|
+
mincol = param(0, state, 0)
|
613
|
+
colinc = param(1, state, 1)
|
614
|
+
minpad = param(2, state, 0)
|
615
|
+
padchar = param(3, state, ?\s).chr
|
616
|
+
arg = state.next_arg
|
617
|
+
# XXX: this needs checking use .to_s here?
|
618
|
+
str = (arg.is_a? String and not @inspect) ? arg.to_s : arg.inspect
|
619
|
+
str = str.send(padmethod, str.length + minpad, padchar)
|
620
|
+
k = ((mincol - str.length) / colinc.to_f).ceil
|
621
|
+
if k > 0
|
622
|
+
str = str.send(padmethod, str.length + colinc * k, padchar)
|
623
|
+
end
|
624
|
+
state.output str
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
628
|
+
# Represents the ~A (Ascii) directive.
|
629
|
+
class Ascii < Print; end
|
630
|
+
|
631
|
+
# Represents the ~S (S-Expression) directive.
|
632
|
+
class SExpression < Print
|
633
|
+
# Sets +inspect+ to +true+ in the argument list.
|
634
|
+
def initialize(*args)
|
635
|
+
super(*args << true)
|
636
|
+
end
|
637
|
+
end
|
638
|
+
|
639
|
+
# Super-class for number printing directives, namely ~D (Decimal, ~B
|
640
|
+
# (Binary), ~O (Octal), and ~X (Hexadecimal). The only difference
|
641
|
+
# between these directives is the output radix, which defaults to ten
|
642
|
+
# (10), which is decimal.
|
643
|
+
class Number < Directive
|
644
|
+
# Create a Number directive, using the given output radix +radix+.
|
645
|
+
def initialize(params, modifiers, top, pos, radix = 10)
|
646
|
+
super params, modifiers, top, pos
|
647
|
+
@radix = radix
|
648
|
+
end
|
649
|
+
|
650
|
+
# Output the given argument using its integral representation. The
|
651
|
+
# argument must respond to the :to_int message, or else it isn't
|
652
|
+
# considered an integer. This is the normal way in which Ruby
|
653
|
+
# operates. The full form is
|
654
|
+
# ~mincol,padchar,commachar,commainterval:@[DBOX]
|
655
|
+
# with the following interpretations
|
656
|
+
# [+mincol+ (0)]
|
657
|
+
# minimum number of columns to output,
|
658
|
+
# [+padchar+ (?\s)]
|
659
|
+
# character to pad with,
|
660
|
+
# [+commachar+ (,)]
|
661
|
+
# character to use for number grouping (see : below),
|
662
|
+
# [+commainterval+ (3)]
|
663
|
+
# how often to output +commachar+ above,
|
664
|
+
# [:]
|
665
|
+
# the number is output, with numbers grouped into +commainterval+
|
666
|
+
# sized groups of numbers, using +commachar+ as separator,
|
667
|
+
# [@]
|
668
|
+
# numbers are always output with sign prepended.
|
669
|
+
#
|
670
|
+
# An ArgumentError is raised if the argument does not respond to the
|
671
|
+
# #to_int message.
|
672
|
+
def execute(state)
|
673
|
+
mincol = param(0, state, 0)
|
674
|
+
padchar = param(1, state, ?\s).chr
|
675
|
+
commachar = param(2, state, ?,).chr
|
676
|
+
interval = param(3, state, 3)
|
677
|
+
arg = state.next_arg
|
678
|
+
if arg.respond_to? :to_int
|
679
|
+
num = arg.to_int
|
680
|
+
str = num.to_s(@radix)
|
681
|
+
if colon_mod?
|
682
|
+
str.gsub!(/(\d)(?=(\d{#{interval}})+(?!\d))/, "\\1#{commachar}")
|
683
|
+
end
|
684
|
+
str = '+' + str if at_mod? and num >= 0
|
685
|
+
# puts(str.rjust(mincol, '-'))
|
686
|
+
state.output str.rjust(mincol, padchar)
|
687
|
+
else
|
688
|
+
arg_error 'argument is not an integer'
|
689
|
+
end
|
690
|
+
end
|
691
|
+
end
|
692
|
+
|
693
|
+
# Represents the ~D (Decimal) directive.
|
694
|
+
class Decimal < Number; end
|
695
|
+
|
696
|
+
# Represents the ~B (Binary) directive.
|
697
|
+
class Binary < Number
|
698
|
+
# Set +radix+ to 2.
|
699
|
+
def initialize(args)
|
700
|
+
super(*args << 2)
|
701
|
+
end
|
702
|
+
end
|
703
|
+
|
704
|
+
# Represents the ~O (Octal) directive.
|
705
|
+
class Octal < Number
|
706
|
+
# Set +radix+ to 8.
|
707
|
+
def initialize(args)
|
708
|
+
super(*args << 8)
|
709
|
+
end
|
710
|
+
end
|
711
|
+
|
712
|
+
# Represents the ~X (Hexadecimal) directive.
|
713
|
+
class Hexadecimal < Number
|
714
|
+
# Set +radix+ to 16.
|
715
|
+
def initialize(args)
|
716
|
+
super(*args << 16)
|
717
|
+
end
|
718
|
+
end
|
719
|
+
|
720
|
+
# Represents the ~R (Radix) directive. This outputs numbers in a given
|
721
|
+
# radix, or using alternative forms, such as Roman numerals or
|
722
|
+
# cardinal/ordinal English numbers.
|
723
|
+
class Radix < Directive
|
724
|
+
@@names = {
|
725
|
+
1 => 'one', 2 => 'two', 3 => 'three',
|
726
|
+
4 => 'four', 5 => 'five', 6 => 'six',
|
727
|
+
7 => 'seven', 8 => 'eight', 9 => 'nine',
|
728
|
+
10 => 'ten', 11 => 'eleven', 12 => 'twelve',
|
729
|
+
13 => 'thirteen', 14 => 'fourteen', 15 => 'fifteen',
|
730
|
+
16 => 'sixteen', 17 => 'seventeen', 18 => 'eighteen',
|
731
|
+
19 => 'nineteen', 20 => 'twenty', 30 => 'thirty',
|
732
|
+
40 => 'forty', 50 => 'fifty', 60 => 'sixty',
|
733
|
+
70 => 'seventy', 80 => 'eighty', 90 => 'ninety'
|
734
|
+
}
|
735
|
+
@@illions = %w[ \
|
736
|
+
thousand million billion trillion
|
737
|
+
quadrillion quintillion sextillion septillion
|
738
|
+
octillion nonillion decillion undecillion
|
739
|
+
duodecillion tredecillion quattuordecillion quindecillion
|
740
|
+
sexdecillion septendecillion octodecillion novemdecillion
|
741
|
+
vigintillion
|
742
|
+
]
|
743
|
+
@@ordinal_ones = %w[
|
744
|
+
\ first second third fourth
|
745
|
+
fifth sixth seventh eight ninth
|
746
|
+
tenth eleventh twelfth thirteenth fourteenth
|
747
|
+
fifteenth sixteenth seventeenth eighteenth nineteenth
|
748
|
+
]
|
749
|
+
@@ordinal_tens = %w[
|
750
|
+
\ \ twentieth thirtieth fortieth
|
751
|
+
fiftieth sixtieth seventieth eightieth ninetieth
|
752
|
+
]
|
753
|
+
@@romans = [
|
754
|
+
[1000, 'M'], [900, 'CM'], [500, 'D'], [400, 'CD'], [100, 'C'],
|
755
|
+
[90, 'XC'], [50, 'L'], [40, 'XL'], [10, 'X'], [9, 'IX'],
|
756
|
+
[5, 'V'], [4, 'IV'], [1, 'I']
|
757
|
+
]
|
758
|
+
@@old_romans = [
|
759
|
+
[1000, 'M'], [900, 'DCCCC'], [500, 'D'], [400, 'CCCC'],
|
760
|
+
[100, 'C'], [90, 'LXXXX'], [50, 'L'], [40, 'XXXX'],
|
761
|
+
[10, 'X'], [9, 'VIIII'], [5, 'V'], [4, 'IIII'],
|
762
|
+
[1, 'I']
|
763
|
+
]
|
764
|
+
|
765
|
+
# Output the given argument using one of a variety of methods. Either
|
766
|
+
# the argument is output using a specific radix, using cardinal or
|
767
|
+
# ordinal English numbers, or Roman numerals. The full form is
|
768
|
+
# ~radix,mincol,padchar,commachar,commainterval:@R
|
769
|
+
# with the same interpretation as for ~D (Decimal / Number), but using
|
770
|
+
# the given +radix+ instead. An ArgumentError is raised if the
|
771
|
+
# argument is not an integer, or, in the case of Roman numerals, if the
|
772
|
+
# argument is not a Fixnum value.
|
773
|
+
#
|
774
|
+
# If none of the parameters are given the output instead depends on the
|
775
|
+
# combination of modifiers:
|
776
|
+
# [<em>no modifiers</em>]
|
777
|
+
# the number is output as a cardinal English number,
|
778
|
+
# [:]
|
779
|
+
# the number is output as an ordinal English number,
|
780
|
+
# [@]
|
781
|
+
# the number is output as a Roman numeral,
|
782
|
+
# [:@]
|
783
|
+
# the number is output as an old Roman numeral.
|
784
|
+
#
|
785
|
+
# An ArgumentError is raised if the argument is not an integer.
|
786
|
+
def execute(state)
|
787
|
+
if @params.size > 0
|
788
|
+
# XXX: may be ugly to modify these
|
789
|
+
n = @params.shift.value
|
790
|
+
Factory.build(@params, @modifiers, nil, @pos, n).execute(state)
|
791
|
+
else
|
792
|
+
arg = state.next_arg
|
793
|
+
if arg.respond_to? :to_int
|
794
|
+
conversion = :cardinal
|
795
|
+
conversion = :ordinal if colon_mod?
|
796
|
+
conversion = :roman if at_mod?
|
797
|
+
conversion = :old_roman if colon_mod? and at_mod?
|
798
|
+
state.output self.send(conversion, arg.to_int)
|
799
|
+
else
|
800
|
+
arg_error 'argument is not an integer'
|
801
|
+
end
|
802
|
+
end
|
803
|
+
end
|
804
|
+
|
805
|
+
private
|
806
|
+
|
807
|
+
# Convert the given number to a cardinal English number string.
|
808
|
+
def cardinal(n)
|
809
|
+
return 'zero' if n.zero?
|
810
|
+
out = []
|
811
|
+
negative = n < 0
|
812
|
+
n = n.abs
|
813
|
+
power = 0
|
814
|
+
while n > 0
|
815
|
+
before, after = n.divmod(1000)
|
816
|
+
if after > 0
|
817
|
+
block = cardinal_100s(after) + (power.zero? ? '' : ' ')
|
818
|
+
if power < @@illions.size
|
819
|
+
block << @@illions[power]
|
820
|
+
else
|
821
|
+
block << 'times ten to the ' + (power * 3).to_s + ' power'
|
822
|
+
end
|
823
|
+
out << block
|
824
|
+
end
|
825
|
+
n = before
|
826
|
+
power += 1
|
827
|
+
end
|
828
|
+
negative and out << 'minus'
|
829
|
+
out.reverse.join(', ')
|
830
|
+
end
|
831
|
+
|
832
|
+
# Deal with hundreds for cardinals.
|
833
|
+
def cardinal_100s(n)
|
834
|
+
out = []
|
835
|
+
q, r = n.divmod(100)
|
836
|
+
out << @@names[q] + ' hundred' if q > 0
|
837
|
+
if r >= 20
|
838
|
+
out << @@names[r / 10 * 10] + (r%10>0 ? '-' + @@names[r % 10] : '')
|
839
|
+
elsif r > 0
|
840
|
+
out << @@names[r]
|
841
|
+
end
|
842
|
+
out.join(' ')
|
843
|
+
end
|
844
|
+
|
845
|
+
# Convert the given number to an ordinal English number string.
|
846
|
+
def ordinal(n)
|
847
|
+
return 'zeroth' if n.zero?
|
848
|
+
out = []
|
849
|
+
if n < 0
|
850
|
+
out << 'minus'
|
851
|
+
n = n.abs
|
852
|
+
end
|
853
|
+
hundreds, tens_ones = n.divmod(100)
|
854
|
+
if hundreds > 0
|
855
|
+
out << cardinal(hundreds * 100) + (tens_ones.zero? ? 'th' : '')
|
856
|
+
end
|
857
|
+
if tens_ones >= 20
|
858
|
+
tens, ones = tens_ones.divmod(10)
|
859
|
+
if ones.zero?
|
860
|
+
out << @@ordinal_tens[tens]
|
861
|
+
else
|
862
|
+
out << @@names[tens * 10] + '-' + @@ordinal_ones[ones]
|
863
|
+
end
|
864
|
+
elsif tens_ones > 0
|
865
|
+
out << @@ordinal_ones[tens_ones]
|
866
|
+
end
|
867
|
+
out.join(' ')
|
868
|
+
end
|
869
|
+
|
870
|
+
# Helper method for roman numerals.
|
871
|
+
def roman_helper(n, table)
|
872
|
+
unless n.is_a? Fixnum
|
873
|
+
arg_error 'only Fixnum values can be converted to roman numerals'
|
874
|
+
end
|
875
|
+
out = []
|
876
|
+
table.each do |decimal, roman|
|
877
|
+
q, r = n.divmod(decimal)
|
878
|
+
if q > 0
|
879
|
+
out << roman * q
|
880
|
+
n = r
|
881
|
+
end
|
882
|
+
end
|
883
|
+
out.join('')
|
884
|
+
end
|
885
|
+
|
886
|
+
# Convert the given number to a Roman numeral.
|
887
|
+
def roman(n)
|
888
|
+
roman_helper(n, @@romans)
|
889
|
+
end
|
890
|
+
|
891
|
+
# Convert the given number to an old Roman numeral.
|
892
|
+
def old_roman(n)
|
893
|
+
roman_helper(n, @@old_romans)
|
894
|
+
end
|
895
|
+
end
|
896
|
+
|
897
|
+
# Represents the ~R (Plural) directive. It outputs English plural
|
898
|
+
# suffixes depending on the given argument.
|
899
|
+
class Plural < Directive
|
900
|
+
# Outputs the given argument as an English plural suffix depending on
|
901
|
+
# the arguments value. If arg is not #eql? to 1, a lowercase +s+ is
|
902
|
+
# output, else nothing is output. The meaning of modifiers are:
|
903
|
+
# [:]
|
904
|
+
# backs up one argument before checking,
|
905
|
+
# [@]
|
906
|
+
# outputs +y+ or +ies+ instead of +s+ and _nothing_,
|
907
|
+
# [:@]
|
908
|
+
# a combination of the two above.
|
909
|
+
def execute(state)
|
910
|
+
arg = colon_mod? ? state.previous_arg : state.next_arg
|
911
|
+
if at_mod?
|
912
|
+
state.output((arg.eql? 1) ? 'y' : 'ies')
|
913
|
+
else
|
914
|
+
state.output(?s) unless arg.eql? 1
|
915
|
+
end
|
916
|
+
end
|
917
|
+
end
|
918
|
+
|
919
|
+
# Represents the ~C (Character) directive. It outputs a character
|
920
|
+
# argument in one of several different representations depending on given
|
921
|
+
# modifiers.
|
922
|
+
# TODO: UNICODE this shit.
|
923
|
+
class Character < Directive
|
924
|
+
# Outputs the given argument in one of the ways described in the table
|
925
|
+
# below depending on given modifiers:
|
926
|
+
# [<tt>no modifiers</tt>]
|
927
|
+
# simply output the character as a normal character,
|
928
|
+
# [:]
|
929
|
+
# spells out control-bits on the input character, such as
|
930
|
+
# Control-Meta-X,
|
931
|
+
# [@]
|
932
|
+
# outputs the character in such as way that it can be read in by the
|
933
|
+
# Ruby interpreter again as input, using the ?_char_ syntax,
|
934
|
+
# [:@]
|
935
|
+
# has the same effect as : only. The CLTL2 suggests that this
|
936
|
+
# outputs unusual shift keys in a manner to make it easy to locate
|
937
|
+
# them on a keyboard, but since no such standard has arisen, this is
|
938
|
+
# not done.
|
939
|
+
def execute(state)
|
940
|
+
arg = state.next_arg
|
941
|
+
arg_error 'argument not a Fixnum' unless arg.is_a? Fixnum
|
942
|
+
ch = arg & 0xff
|
943
|
+
if colon_mod?
|
944
|
+
state.output('Control-') if (ch & 0x7f) < 0x1f
|
945
|
+
state.output('Meta-') if ch >= 0x7f
|
946
|
+
state.output(ch & 0x7f | 0x60)
|
947
|
+
elsif at_mod?
|
948
|
+
state.output('?' + convert_char(ch))
|
949
|
+
else
|
950
|
+
state.output ch
|
951
|
+
end
|
952
|
+
end
|
953
|
+
|
954
|
+
private
|
955
|
+
|
956
|
+
# Convert a character to a escaped character string if possible.
|
957
|
+
# XXX: This should perhaps only use \x or \NNN syntax
|
958
|
+
def convert_char(ch)
|
959
|
+
if [?\\, ?\n, ?\t, ?\r, ?\f, ?\v, ?\a, ?\e, ?\b, ?\s].include? ch
|
960
|
+
ch.chr.inspect[1..-2]
|
961
|
+
else
|
962
|
+
if (ch & 0x7f) < 0x1f
|
963
|
+
"\\C-" + convert_char(ch | 0x60)
|
964
|
+
elsif ch >= 0x7f
|
965
|
+
"\\M-" + convert_char(ch & 0x7f | 0x60)
|
966
|
+
else
|
967
|
+
ch
|
968
|
+
end
|
969
|
+
end
|
970
|
+
end
|
971
|
+
end
|
972
|
+
|
973
|
+
# Represents the ~F (Fixed-format floating-point) directive. This
|
974
|
+
# outputs floating point values with various kinds of padding and such.
|
975
|
+
class FFFP < Directive
|
976
|
+
# Outputs the given argument using a floating-point representation.
|
977
|
+
# The full form is
|
978
|
+
# ~w,d,k,overflowchar,padchar@F
|
979
|
+
# with the following interpretations
|
980
|
+
# [+w+ (+nil+)]
|
981
|
+
# if non-+nil+, the output will be exactly +w+ characters long,
|
982
|
+
# [+d+ (+nil+)]
|
983
|
+
# if non-+nil+, this is the number of digits output after the decimal
|
984
|
+
# point (<tt>.</tt>),
|
985
|
+
# [+k+ (0)]
|
986
|
+
# scaling factor - the number is first scaled using this value,
|
987
|
+
# [+overflowchar+ (+nil+)]
|
988
|
+
# if non-+nil+, this character is used when this directive would
|
989
|
+
# produce output longer than that specified with the +w+ directive,
|
990
|
+
# [+padchar+ (?\s)]
|
991
|
+
# character to pad with if +w+ is non-nil and output isn't wide
|
992
|
+
# enough yet,
|
993
|
+
# [@]
|
994
|
+
# numbers are always output with sign prepended.
|
995
|
+
#
|
996
|
+
# An ArgumentError is raised if the argument is not a number or a
|
997
|
+
# string that can be converted to a number.
|
998
|
+
def execute(state)
|
999
|
+
width = param(0, state, nil)
|
1000
|
+
digits = param(1, state, nil)
|
1001
|
+
scale = param(2, state, 0)
|
1002
|
+
overflowchar = param(3, state, nil)
|
1003
|
+
padchar = param(4, state, ?\s)
|
1004
|
+
arg = state.next_arg
|
1005
|
+
if arg.respond_to? :to_f
|
1006
|
+
num = arg.to_f * (10 ** scale)
|
1007
|
+
str = (at_mod? and num >= 0) ? '+' : ''
|
1008
|
+
str = sign + (digits.nil? ? num.to_s : sprintf("%.#{digits}f",num))
|
1009
|
+
str = sign + sprintf("%.#{$1}f", num) if str =~ /e-([0-9]+)$/
|
1010
|
+
unless width.nil?
|
1011
|
+
if not digits.nil? and width == digits + 1
|
1012
|
+
str.sub!(/^([+-]?)0\./, '\1.')
|
1013
|
+
end
|
1014
|
+
str = str.rjust(width, padchar.chr) if str.length < width
|
1015
|
+
if str.length > width and digits.nil?
|
1016
|
+
prec = width - (str.index(/\./) + 1)
|
1017
|
+
str = sign + sprintf("%#.#{prec}f", num)
|
1018
|
+
end
|
1019
|
+
str.sub!(/\.$/, '') if str.length > width and digits.nil?
|
1020
|
+
if str.length > width and not overflowchar.nil?
|
1021
|
+
str = overflowchar.chr * width
|
1022
|
+
end
|
1023
|
+
end
|
1024
|
+
state.output str
|
1025
|
+
elsif arg.respond_to? :to_int
|
1026
|
+
state.push_back_arg
|
1027
|
+
parameters = @params[0].nil? ? [] : [@params[0]]
|
1028
|
+
Factory.build(parameters, [], ?D, nil, @pos).execute(state)
|
1029
|
+
else
|
1030
|
+
arg_error 'argument is not a number or a number string'
|
1031
|
+
end
|
1032
|
+
end
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
# Represents the ~E (Exponential floating-point) directive. This outputs
|
1036
|
+
# floating point values in what is known as exponential or scientific
|
1037
|
+
# floating point format, such as 1.0e+3 for 1000.
|
1038
|
+
class ExpFP < Directive
|
1039
|
+
|
1040
|
+
# Outputs the argument using exponential floating-point format. The
|
1041
|
+
# full form is
|
1042
|
+
# ~w,d,e,k,overflowchar,padchar,exponentchar@E
|
1043
|
+
# with the following interpretations
|
1044
|
+
# [+w+ (+nil+)]
|
1045
|
+
# if non-+nil+, the output will be exactly +w+ characters long,
|
1046
|
+
# [+d+ (+nil+)]
|
1047
|
+
# if non-+nil+, this is the number of digits output after the decimal
|
1048
|
+
# point (<tt>.</tt>),
|
1049
|
+
# [+e+ (+nil+)]
|
1050
|
+
# if non-+nil+, the exponent part of the output will be exactly +e+
|
1051
|
+
# characters long,
|
1052
|
+
# [+k+ (1)]
|
1053
|
+
# scaling factor - the number is first scaled using this value,
|
1054
|
+
# [+overflowchar+ (+nil+)]
|
1055
|
+
# if non-+nil+, this character is used when this directive would
|
1056
|
+
# produce output longer than that specified with the +w+ directive,
|
1057
|
+
# [+padchar+ (?\s)]
|
1058
|
+
# character to pad with if +w+ is non-nil and output isn't wide
|
1059
|
+
# enough yet,
|
1060
|
+
# [+exponentchar+ (?e)]
|
1061
|
+
# character to use for exponent divider,
|
1062
|
+
# [@]
|
1063
|
+
# numbers are always output with sign prepended.
|
1064
|
+
#
|
1065
|
+
# An ArgumentError is raised if the argument is not a number or a
|
1066
|
+
# string that can be converted to a number.
|
1067
|
+
def execute(state)
|
1068
|
+
width = param(0, state, nil)
|
1069
|
+
digits = param(1, state, nil)
|
1070
|
+
edigits = param(2, state, nil)
|
1071
|
+
scale = param(3, state, 1)
|
1072
|
+
overflowchar = param(4, state, nil)
|
1073
|
+
padchar = param(5, state, ?\s).chr
|
1074
|
+
exponentchar = param(6, state, ?e).chr
|
1075
|
+
arg = state.next_arg
|
1076
|
+
if arg.respond_to? :to_f
|
1077
|
+
num = arg.to_f
|
1078
|
+
sign = (num >= 0 and at_mod?) ? '+' : ''
|
1079
|
+
exp = Math.log10(num.abs).floor - (scale - 1)
|
1080
|
+
exp_str = exponentchar + (exp >= 0 ? '+' : '-') +
|
1081
|
+
(edigits.nil? ? exp.abs.to_s : exp.abs.to_s.rjust(edigits, '0'))
|
1082
|
+
if digits.nil? and width.nil? and edigits.nil?
|
1083
|
+
str = sign + (num * (10 ** -exp)).to_s + exp_str
|
1084
|
+
else
|
1085
|
+
if digits.nil?
|
1086
|
+
prec = width - sign.length -
|
1087
|
+
((num * (10 ** -exp)).to_s.index(/\./) + 1) - exp_str.length
|
1088
|
+
str = sign + sprintf("%#.#{prec}f", num) + exp_str
|
1089
|
+
else
|
1090
|
+
if scale > 0
|
1091
|
+
if scale < digits + 2
|
1092
|
+
prec = digits - scale + 1
|
1093
|
+
else
|
1094
|
+
param_error 3, 'scale must be < digits + 2'
|
1095
|
+
end
|
1096
|
+
else
|
1097
|
+
prec = -scale + (digits + scale)
|
1098
|
+
end
|
1099
|
+
str = sign + sprintf("%#.#{prec}f", num * (10**-exp)) + exp_str
|
1100
|
+
end
|
1101
|
+
unless width.nil?
|
1102
|
+
if scale <= 0 and str.length > width
|
1103
|
+
str.sub!(/^([+-]?)0\./, '\1.')
|
1104
|
+
end
|
1105
|
+
str = str.rjust(width, padchar) if str.length < width
|
1106
|
+
end
|
1107
|
+
unless width.nil? and overflowchar.nil?
|
1108
|
+
if not edigits.nil? and (exp_str.length - 2) > edigits
|
1109
|
+
str = overflowchar.chr * width
|
1110
|
+
end
|
1111
|
+
end
|
1112
|
+
end
|
1113
|
+
state.output str
|
1114
|
+
elsif arg.respond_to? :to_int
|
1115
|
+
state.push_back_arg
|
1116
|
+
parameters = @params[0].nil? ? [] : [@params[0]]
|
1117
|
+
Factory.build(parameters, [], ?D, nil, @pos).execute(state)
|
1118
|
+
else
|
1119
|
+
arg_error 'argument is not a number or a number string'
|
1120
|
+
end
|
1121
|
+
end
|
1122
|
+
end
|
1123
|
+
|
1124
|
+
# Represents the ~G (General floating-point) directive. This outputs its
|
1125
|
+
# argument using either a format like ~F or ~E depending upon given
|
1126
|
+
# parameters and the magnitude of the argument.
|
1127
|
+
class GeneralFP < Directive
|
1128
|
+
# Outputs the argument using exponential floating-point format. The
|
1129
|
+
# algorithm to decide what format to use looks something like
|
1130
|
+
# let
|
1131
|
+
# 10^n-1 <= arg < 10^n, or n = 0 if arg = 0,
|
1132
|
+
# ee = e + 2, or ee = 4 if e undefined,
|
1133
|
+
# ww = w - ee, or ww = nil if w undefined,
|
1134
|
+
# dd = d - n, or dd = max(q, min(n, 7)) where q = number of
|
1135
|
+
# characters necessary to print arg without loss of information
|
1136
|
+
# in
|
1137
|
+
# 0 <= dd <= d, and print using
|
1138
|
+
# ~ww,dd,,overflowchar,padcharF~ee@T
|
1139
|
+
# or print using
|
1140
|
+
# ~w,d,e,k,overflowchar,padchar,exponentcharG
|
1141
|
+
# Use of the @ modifier in the directives above depends on if it was
|
1142
|
+
# passed to ~G in the first place.
|
1143
|
+
#
|
1144
|
+
# The full form is
|
1145
|
+
# ~w,d,e,k,overflowchar,padchar,exponentchar@G
|
1146
|
+
# with the following interpretations
|
1147
|
+
# [+w+ (+nil+)]
|
1148
|
+
# if non-+nil+, the output will be exactly +w+ characters long,
|
1149
|
+
# [+d+ (+nil+)]
|
1150
|
+
# if non-+nil+, this is the number of digits output after the decimal
|
1151
|
+
# point (<tt>.</tt>),
|
1152
|
+
# [+e+ (+nil+)]
|
1153
|
+
# if non-+nil+, the exponent part of the output will be exactly +e+
|
1154
|
+
# characters long,
|
1155
|
+
# [+k+ (1)]
|
1156
|
+
# scaling factor - the number is first scaled using this value,
|
1157
|
+
# [+overflowchar+ (+nil+)]
|
1158
|
+
# if non-+nil+, this character is used when this directive would
|
1159
|
+
# produce output longer than that specified with the +w+ directive,
|
1160
|
+
# [+padchar+ (?\s)]
|
1161
|
+
# character to pad with if +w+ is non-nil and output isn't wide
|
1162
|
+
# enough yet,
|
1163
|
+
# [+exponentchar+ (?e)]
|
1164
|
+
# character to use for exponent divider,
|
1165
|
+
# [@]
|
1166
|
+
# numbers are always output with sign prepended.
|
1167
|
+
#
|
1168
|
+
# An ArgumentError is raised if the argument is not a number or a
|
1169
|
+
# string that can be converted to a number.
|
1170
|
+
def execute(state)
|
1171
|
+
width = param(0, state, nil)
|
1172
|
+
digits = param(1, state, nil)
|
1173
|
+
edigits = param(2, state, nil)
|
1174
|
+
scale = param(3, state, 1)
|
1175
|
+
overflowchar = param(4, state, nil)
|
1176
|
+
padchar = param(5, state, ?\s)
|
1177
|
+
exponentchar = param(6, state, nil)
|
1178
|
+
arg = state.next_arg
|
1179
|
+
if arg.respond_to? :to_f
|
1180
|
+
num = arg.to_f
|
1181
|
+
n = num == 0.0 ? 0 : Math.log10(num.abs).floor + 1
|
1182
|
+
ee = edigits.nil? ? 4 : edigits + 2
|
1183
|
+
ww = w.nil? ? nil : w - ee
|
1184
|
+
if d.nil?
|
1185
|
+
q = num.to_s.length
|
1186
|
+
d = Math.max(q, Math.min(n, 7))
|
1187
|
+
end
|
1188
|
+
dd = d - n
|
1189
|
+
if 0 <= dd and dd <= d
|
1190
|
+
state.push_back_arg
|
1191
|
+
parameters = [
|
1192
|
+
Parameters::Integer.new(@pos, ww),
|
1193
|
+
Parameters::Integer.new(@pos, dd),
|
1194
|
+
Parameters::Default.new(@pos),
|
1195
|
+
overflowchar.nil? ?
|
1196
|
+
Parameters::Default.new(@pos) :
|
1197
|
+
Parameters::Character.new(@pos, overflowchar),
|
1198
|
+
padchar.nil? ?
|
1199
|
+
Parameters::Default.new(@pos) :
|
1200
|
+
Parameters::Character.new(@pos, padchar),
|
1201
|
+
]
|
1202
|
+
Factory.build(parameters, @modifiers, ?F, nil,
|
1203
|
+
@pos).execute(state)
|
1204
|
+
Factory.build([Parameters::Integere.new(@pos, ee)], @modifiers,
|
1205
|
+
?T, nil, @pos).execute(state)
|
1206
|
+
else
|
1207
|
+
state.push_back_arg
|
1208
|
+
Factory.build(@params, @modifiers, ?E, nil, @pos).execute(state)
|
1209
|
+
end
|
1210
|
+
elsif arg.respond_to? :to_int
|
1211
|
+
state.push_back_arg
|
1212
|
+
parameters = @params[0].nil? ? [] : [@params[0]]
|
1213
|
+
Factory.build(parameters, [], ?D, nil, @pos).execute(state)
|
1214
|
+
else
|
1215
|
+
arg_error 'argument is not a number or a number string'
|
1216
|
+
end
|
1217
|
+
end
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
# Represents the ~$ (Dollars floating-point) directive. This directive
|
1221
|
+
# outputs a floating point argument
|
1222
|
+
class DollarFP < Directive
|
1223
|
+
# Outputs the argument using a floating point format that suits dollar
|
1224
|
+
# values. The full form is
|
1225
|
+
# ~d,n,w,padchar:@$
|
1226
|
+
# with the following interpretations
|
1227
|
+
# [+d+ (2)]
|
1228
|
+
# number of digits to print after the decimal point (<tt>.</tt>),
|
1229
|
+
# [+n+ (1)]
|
1230
|
+
# number of digits to print before the decimal point (<tt>.</tt>),
|
1231
|
+
# [+w+ (0)]
|
1232
|
+
# minimum width of the field,
|
1233
|
+
# [+padchar+ (?\s)]
|
1234
|
+
# character used to produce right-adjusting padding with,
|
1235
|
+
# [:]
|
1236
|
+
# the sign of the value is output before any padding,
|
1237
|
+
# [@]
|
1238
|
+
# numbers are always output with sign prepended.
|
1239
|
+
def execute(state)
|
1240
|
+
digits = param(0, state, 2)
|
1241
|
+
idigits = param(1, state, 1)
|
1242
|
+
width = param(2, state, 0)
|
1243
|
+
padchar = param(3, state, ?\s)
|
1244
|
+
arg = state.next_arg
|
1245
|
+
if arg.respond_to :to_int
|
1246
|
+
sign = (arg >= 0 ? (at_mod? ? '+' : '') : '-')
|
1247
|
+
str = sprintf("%0#{idigits + digits + 1}.#{digits}f", arg.abs)
|
1248
|
+
if colon_mod?
|
1249
|
+
str = sign + str.rjust(width, padchar.chr)
|
1250
|
+
else
|
1251
|
+
str = (sign + str).rjust(width, padchar.chr)
|
1252
|
+
end
|
1253
|
+
state.output str
|
1254
|
+
elsif arg.respond_to? :to_i
|
1255
|
+
state.push_back_arg
|
1256
|
+
parameters = @params[2].nil? ? [] : [@params[2]]
|
1257
|
+
Factory.build(?D, parameters, [], nil, @pos).execute(state)
|
1258
|
+
else
|
1259
|
+
arg_error 'argument is not a number or a number string'
|
1260
|
+
end
|
1261
|
+
end
|
1262
|
+
end
|
1263
|
+
|
1264
|
+
# Parent class for character outputting directives, such as ~% (NewLine),
|
1265
|
+
# ~| (NewPage), and ~~ (Tilde), which output the same character a given
|
1266
|
+
# number of times.
|
1267
|
+
class CharacterDirective < Directive
|
1268
|
+
# Create and set the character to use to +ch+.
|
1269
|
+
def initialize(params, modifiers, top, pos, ch)
|
1270
|
+
super params, modifiers, top, pos
|
1271
|
+
@ch = ch
|
1272
|
+
end
|
1273
|
+
|
1274
|
+
# Outputs the specific character (depending on the
|
1275
|
+
# sub-classing directive) a given number of times. The full form is
|
1276
|
+
# ~n[%|~]
|
1277
|
+
# with the following interpretations
|
1278
|
+
# [+n+ (1)]
|
1279
|
+
# number of times to output the specific character.
|
1280
|
+
def execute(state)
|
1281
|
+
n = param(0, state, 1)
|
1282
|
+
state.output(@ch.chr * n)
|
1283
|
+
end
|
1284
|
+
end
|
1285
|
+
|
1286
|
+
# Represents the ~% (Newline) directive. This outputs a new-line (?\n)
|
1287
|
+
# character a given number of times.
|
1288
|
+
class NewLine < CharacterDirective
|
1289
|
+
# Set the output character to a new-line (?\n).
|
1290
|
+
def initialize(*args)
|
1291
|
+
super(*args << ?\n)
|
1292
|
+
end
|
1293
|
+
end
|
1294
|
+
|
1295
|
+
# Represents the ~% (Freshline) directive. This outputs a new-line (?\n)
|
1296
|
+
# character a given number of times, depending on if it is already at the
|
1297
|
+
# first output column or not.
|
1298
|
+
class FreshLine < Directive
|
1299
|
+
# Outputs a new-line character a given number of times depending on if
|
1300
|
+
# it is already at the first output column or not. If it is it outputs
|
1301
|
+
# it the given number minus one (1). The full form is
|
1302
|
+
# ~n&
|
1303
|
+
# with the following interpretations
|
1304
|
+
# [+n+ (1)]
|
1305
|
+
# number of times to output the specific character (maybe minus one).
|
1306
|
+
def execute(state)
|
1307
|
+
n = param(0, state, 1)
|
1308
|
+
return if n.zero?
|
1309
|
+
state.output(?\n) if state._col > 0
|
1310
|
+
(n - 1).times do state.output(?\n) end
|
1311
|
+
end
|
1312
|
+
end
|
1313
|
+
|
1314
|
+
# Represents the ~| (Newpage) directive. This outputs a new-page (?\f)
|
1315
|
+
# character a given number of times.
|
1316
|
+
class NewPage < CharacterDirective
|
1317
|
+
# Set the output character to a new-page (?\f).
|
1318
|
+
def initialize(*args)
|
1319
|
+
super(*args << ?\f)
|
1320
|
+
end
|
1321
|
+
end
|
1322
|
+
|
1323
|
+
# Represents the ~~ (Tilde) directive. This outputs a tilde (~)
|
1324
|
+
# character a given number of times.
|
1325
|
+
class Tilde < CharacterDirective
|
1326
|
+
# Set the output character to a tilde (~).
|
1327
|
+
def initialize(*args)
|
1328
|
+
super(*args << ?~)
|
1329
|
+
end
|
1330
|
+
end
|
1331
|
+
|
1332
|
+
# Represents the ~?\n (Real new-line) directive. This is used to skip
|
1333
|
+
# the new-line and any following white-space characters in the input
|
1334
|
+
# format. This is useful in long format strings, where the string has to
|
1335
|
+
# be split into multiple lines without ruining indentation.
|
1336
|
+
class SkipWhitespace < Directive
|
1337
|
+
# Join this directive with the following. This removes any new-line
|
1338
|
+
# and/or following white-space from the directive that follows, if it
|
1339
|
+
# is a string Literal.
|
1340
|
+
def join(other)
|
1341
|
+
return other if not other.is_a?(FormatLiteral) or colon_mod?
|
1342
|
+
other.sub!(/^[\s\t]+/, '')
|
1343
|
+
other[0,0] = '\n' if at_mod?
|
1344
|
+
other
|
1345
|
+
end
|
1346
|
+
end
|
1347
|
+
|
1348
|
+
# Represents the ~T (Tabulate) directive. This tabulates to a given
|
1349
|
+
# position in the output using white-space.
|
1350
|
+
class Tabulate < Directive
|
1351
|
+
# The output is spaced over to a given position, depending on where it
|
1352
|
+
# already is and parameters given to this directive.
|
1353
|
+
# ~colnum,colinc:@T
|
1354
|
+
# with the following interpretations
|
1355
|
+
# [+colnum+ (1)]
|
1356
|
+
# column to move to,
|
1357
|
+
# [+colinc+ (1)]
|
1358
|
+
# number of columns to space over by if already at or beyond
|
1359
|
+
# +colnum+,
|
1360
|
+
# [@]
|
1361
|
+
# performs relative tabulation. +colnum+ is treated as the column to
|
1362
|
+
# begin from (spacing over to it if necessary), and then moves over
|
1363
|
+
# to a column that is the smallest multiple of +colinc+.
|
1364
|
+
#
|
1365
|
+
# If output is already at or beyond +colnum+, then output is spaced
|
1366
|
+
# over to column <em>colnum + k * colinc</em>, for the smallest _k_
|
1367
|
+
# possible. An example of the @ modifiers effect is for the instance
|
1368
|
+
# of the ~T directive ~3,8@T, which moves over three columns, and then
|
1369
|
+
# to the first eight-sized tab-stop.
|
1370
|
+
def execute(state)
|
1371
|
+
colnum = param(0, state, 1)
|
1372
|
+
colinc = param(1, state, 1)
|
1373
|
+
padchar = ?\s.chr
|
1374
|
+
if at_mod?
|
1375
|
+
state.output(padchar * colnum)
|
1376
|
+
state.output(padchar * (colinc - state.col % colinc))
|
1377
|
+
else
|
1378
|
+
if state.col < colnum
|
1379
|
+
state.output(padchar * (colnum - state.col))
|
1380
|
+
elsif colinc > 0
|
1381
|
+
k = 1 + (state.col - colnum) / colinc
|
1382
|
+
state.output(padchar * ((colnum + k * colinc) - state.col))
|
1383
|
+
end
|
1384
|
+
end
|
1385
|
+
end
|
1386
|
+
end
|
1387
|
+
|
1388
|
+
# Represents the ~* (Argument jumping) directive. This moves arbitrarily
|
1389
|
+
# amongst the arguments passed to the formatting engine.
|
1390
|
+
class ArgJump < Directive
|
1391
|
+
# Moves backwards or forwards, relative or absolute, among the
|
1392
|
+
# formatting arguments. The full form is
|
1393
|
+
# ~n:@*
|
1394
|
+
# with the following interpretations
|
1395
|
+
# [+n+ (1)]
|
1396
|
+
# the amount of arguments to move or the argument to move to if
|
1397
|
+
# moving to an absolute position, indexed from zero (0),
|
1398
|
+
# [:]
|
1399
|
+
# move backwards +n+ arguments
|
1400
|
+
# [@]
|
1401
|
+
# move to the +n+:th argument, using zero-based indexing (absolute).
|
1402
|
+
def execute(state)
|
1403
|
+
n = param(0, state, 1)
|
1404
|
+
state.args_move(colon_mod? ? -n : n, !at_mod?)
|
1405
|
+
end
|
1406
|
+
end
|
1407
|
+
|
1408
|
+
# Represents the ~? (Indirection) directive. This takes the two
|
1409
|
+
# following arguments and formats them, using the first as the formatting
|
1410
|
+
# string, and the second as its arguments and inserts it into the output.
|
1411
|
+
class Indirection < Directive
|
1412
|
+
# Uses the next argument as a formatting string and then, depending on
|
1413
|
+
# modifiers specified, uses one of a set of different arguments as
|
1414
|
+
# input to this formatting. The full form is
|
1415
|
+
# ~@?
|
1416
|
+
# with the following interpretations
|
1417
|
+
# [@]
|
1418
|
+
# the formatting string is, much like a macro, inserted into the
|
1419
|
+
# formatting stream, so to speak, and consumes arguments and so on
|
1420
|
+
# from the current state, instead, as per default, consuming a second
|
1421
|
+
# argument and reading arguments from it.
|
1422
|
+
def execute(state)
|
1423
|
+
if at_mod?
|
1424
|
+
formatter = Formatter.new(state.next_arg, state)
|
1425
|
+
else
|
1426
|
+
format = state.next_arg
|
1427
|
+
state = State.new(state.next_arg, state.latest_output)
|
1428
|
+
formatter = Formatter.new(format, state)
|
1429
|
+
end
|
1430
|
+
formatter.run
|
1431
|
+
end
|
1432
|
+
end
|
1433
|
+
|
1434
|
+
# Represents the ~( (Begin case-conversion) directive. Everything
|
1435
|
+
# contained within it and its matching pair ~) (End case-conversion)
|
1436
|
+
# directive is subject to case conversion, such as upcasing or
|
1437
|
+
# capitalization.
|
1438
|
+
class BeginCaseConversion < Directive
|
1439
|
+
# Outputs the contained output case converted using some method that
|
1440
|
+
# depends on the combination of modifiers given to this directive. The
|
1441
|
+
# full form is
|
1442
|
+
# ~:@(
|
1443
|
+
# with the following interpretations
|
1444
|
+
# [<em>no modifiers</em>]
|
1445
|
+
# output is downcased,
|
1446
|
+
# [:]
|
1447
|
+
# every word is capitalized in the output,
|
1448
|
+
# [@]
|
1449
|
+
# the first word is capitalized in the output,
|
1450
|
+
# [:@]
|
1451
|
+
# output is upcased.
|
1452
|
+
def execute(state)
|
1453
|
+
conv = :DOWN
|
1454
|
+
conv = :CAP if colon_mod?
|
1455
|
+
conv = :CAP_FIRST if at_mod?
|
1456
|
+
conv = :UP if colon_mod? and at_mod?
|
1457
|
+
state.case_conv = conv
|
1458
|
+
state.push_output
|
1459
|
+
end
|
1460
|
+
end
|
1461
|
+
|
1462
|
+
# Represents the ~) (End case-conversion) directive. Everything
|
1463
|
+
# contained within it and its matching pair ~( (Begin case-conversion)
|
1464
|
+
# directive is subject to case conversion, such as upcasing or
|
1465
|
+
# capitalization.
|
1466
|
+
class EndCaseConversion < Directive
|
1467
|
+
# This does the actual work for the ~( directive, in that it collects
|
1468
|
+
# all the output between its matching directive (~() and outputs it
|
1469
|
+
# using one of the conversions set up by the ~( (BeginCaseConversion)
|
1470
|
+
# directive.
|
1471
|
+
def execute(state)
|
1472
|
+
output = state.pop_output.to_s
|
1473
|
+
state.output(
|
1474
|
+
case state.case_conv
|
1475
|
+
when :DOWN
|
1476
|
+
output.downcase
|
1477
|
+
when :CAP
|
1478
|
+
output.gsub(/\w+/) do |w| w.capitalize end
|
1479
|
+
when :CAP_FIRST
|
1480
|
+
output.capitalize
|
1481
|
+
when :UP
|
1482
|
+
output.upcase
|
1483
|
+
end
|
1484
|
+
)
|
1485
|
+
end
|
1486
|
+
end
|
1487
|
+
|
1488
|
+
# Represents the ~[ (Begin conditional expression) directive. This is
|
1489
|
+
# useful to choose among a set of directives depending on arguments and
|
1490
|
+
# numbers.
|
1491
|
+
class BeginConditional < Directive
|
1492
|
+
# Set up some variables and basically pass on to super.
|
1493
|
+
def initialize(*args)
|
1494
|
+
super(*args)
|
1495
|
+
if (colon_mod? or at_mod?) and @params.size > 0
|
1496
|
+
param_error 0, 'no parameters allowed together with' +
|
1497
|
+
': and/or @ modifiers'
|
1498
|
+
end
|
1499
|
+
@clauses = []
|
1500
|
+
@default = -1
|
1501
|
+
end
|
1502
|
+
|
1503
|
+
# Process one of the given clauses, depending on the numeric value of
|
1504
|
+
# the given argument, or a specified parameter. The full form is
|
1505
|
+
# ~n[clause0~;clause1~:;clause2~]
|
1506
|
+
# or
|
1507
|
+
# ~:[clause0~;clause1~]
|
1508
|
+
# or
|
1509
|
+
# ~@[clause0~]
|
1510
|
+
# with the following interpretations
|
1511
|
+
# [+n+ (nil)]
|
1512
|
+
# if given, this value will be used to choose a clause instead of
|
1513
|
+
# reading an arguments value. This is only useful if +n+ is in fact
|
1514
|
+
# the arguments left parameter (<tt>#</tt>). An error is raised if
|
1515
|
+
# this argument does not #respond_to? :to_int,
|
1516
|
+
# [:]
|
1517
|
+
# instead of choosing a clause by number, the argument is tested as a
|
1518
|
+
# boolean value, and if false, then first clause is executed, else
|
1519
|
+
# the second one is,
|
1520
|
+
# [@]
|
1521
|
+
# instead of choosing a clause by number, the argument is tested as a
|
1522
|
+
# boolean value, and if true, the single clause is executed.
|
1523
|
+
def execute(state)
|
1524
|
+
test = state.next_arg if colon_mod? or at_mod?
|
1525
|
+
if colon_mod?
|
1526
|
+
c = test ? 1 : 0
|
1527
|
+
elsif at_mod?
|
1528
|
+
if test
|
1529
|
+
state.push_back_arg
|
1530
|
+
c = 0
|
1531
|
+
end
|
1532
|
+
else
|
1533
|
+
n = param(0, state, nil)
|
1534
|
+
if n.nil?
|
1535
|
+
arg = state.next_arg
|
1536
|
+
if arg.respond_to? :to_int
|
1537
|
+
n = arg.to_int
|
1538
|
+
else
|
1539
|
+
arg_error 'argument is not an integral value'
|
1540
|
+
end
|
1541
|
+
end
|
1542
|
+
if n < @clauses.size
|
1543
|
+
c = n
|
1544
|
+
elsif @default != -1
|
1545
|
+
c = @default
|
1546
|
+
end
|
1547
|
+
end
|
1548
|
+
Format.execute_directives(state, @clauses[c]) unless c.nil?
|
1549
|
+
end
|
1550
|
+
|
1551
|
+
# Connect a set of directives to this conditional directive.
|
1552
|
+
# A SyntaxError is raised if multiple clauses have been marked as
|
1553
|
+
# 'default', or if too many clauses have been specified for a given
|
1554
|
+
# set of modifiers.
|
1555
|
+
def connect(directives)
|
1556
|
+
@clauses = []
|
1557
|
+
clause = []
|
1558
|
+
directives.each do |d|
|
1559
|
+
if d.is_a? ClauseSeparator
|
1560
|
+
@clauses << clause
|
1561
|
+
clause = []
|
1562
|
+
if d.colon_mod?
|
1563
|
+
if @default == -1
|
1564
|
+
@default = @clauses.size
|
1565
|
+
else
|
1566
|
+
raise SyntaxError.new(d.pos),
|
1567
|
+
'default clause has already been set'
|
1568
|
+
end
|
1569
|
+
end
|
1570
|
+
elsif d.is_a? EndConditional
|
1571
|
+
@clauses << clause
|
1572
|
+
break
|
1573
|
+
else
|
1574
|
+
clause << d
|
1575
|
+
end
|
1576
|
+
end
|
1577
|
+
must = 'two' if colon_mod? and @clauses.size != 2
|
1578
|
+
must = 'one' if at_mod? and @clauses.size != 1
|
1579
|
+
unless must.nil?
|
1580
|
+
raise SyntaxError.new(@pos), "must specify exactly #{must} clauses"
|
1581
|
+
end
|
1582
|
+
end
|
1583
|
+
end
|
1584
|
+
|
1585
|
+
# Represents the ~; (Clause separator) directive. It separates clauses
|
1586
|
+
# inside conditional and justifying directives (~[...~] and ~<...~>). It
|
1587
|
+
# may not appear anywhere else.
|
1588
|
+
class ClauseSeparator < Directive
|
1589
|
+
# Check that +top+ is either a BeginConditional or a
|
1590
|
+
# BeginJustification. If not, a SyntaxError is raised.
|
1591
|
+
def initialize(params, modifiers, top, pos)
|
1592
|
+
super params, modifiers, top, pos
|
1593
|
+
unless top.is_a? BeginConditional
|
1594
|
+
raise SyntaxError.new(@pos),
|
1595
|
+
'~; directive must be contained within a conditional (~[...~])' +
|
1596
|
+
' or a justification (~<...~>)'
|
1597
|
+
end
|
1598
|
+
end
|
1599
|
+
end
|
1600
|
+
|
1601
|
+
# Represents the ~] (End conditional expression) directive. It ends a
|
1602
|
+
# conditional expression, and is an error if it appears without a
|
1603
|
+
# matching opening conditional expression.
|
1604
|
+
class EndConditional < Directive
|
1605
|
+
def initialize(params, modifiers, top, pos)
|
1606
|
+
super params, modifiers, top, pos
|
1607
|
+
unless top.is_a? BeginConditional
|
1608
|
+
raise SyntaxError.new(@pos), '~) without matching ~('
|
1609
|
+
end
|
1610
|
+
end
|
1611
|
+
end
|
1612
|
+
|
1613
|
+
# Represents the ~{ (Begin iteration) directive. A given set of
|
1614
|
+
# directives is used iteratively over a set of arguments (depends on the
|
1615
|
+
# modifiers specified) a given number of times, or until it runs out of
|
1616
|
+
# arguments.
|
1617
|
+
class BeginIteration < Directive
|
1618
|
+
# Create and set up some private variables
|
1619
|
+
def initialize(params, modifiers, top, pos)
|
1620
|
+
super params, modifiers, top, pos
|
1621
|
+
@directives = []
|
1622
|
+
end
|
1623
|
+
|
1624
|
+
# Iteratively run the contained directives using sets of arguments
|
1625
|
+
# depending upon what modifiers where given. The full form is
|
1626
|
+
# ~n:@{...~}
|
1627
|
+
# with the following interpretations
|
1628
|
+
# [n]
|
1629
|
+
# maximum number of times the iteration should be performed,
|
1630
|
+
# [<em>no modifiers</em>]
|
1631
|
+
# the iteration reads an argument, which must be an Array, and uses
|
1632
|
+
# it as the arguments to the contained directives,
|
1633
|
+
# [:]
|
1634
|
+
# the iteration reads an argument, which must be an Array
|
1635
|
+
# containing sub-arrays, and uses the sub-arrays as the arguments to
|
1636
|
+
# the contained directives, moving to the next one on each iteration,
|
1637
|
+
# [@]
|
1638
|
+
# the iteration uses the rest of the arguments as arguments to the
|
1639
|
+
# contained directives,
|
1640
|
+
# [:@]
|
1641
|
+
# the iteration uses the rest of the arguments, which must be Arrays,
|
1642
|
+
# using each Array as the set of arguments to the contained
|
1643
|
+
# directives.
|
1644
|
+
def execute(state)
|
1645
|
+
n = param(0, state, nil)
|
1646
|
+
return if not n.nil? and n == 0
|
1647
|
+
if colon_mod? and at_mod?
|
1648
|
+
execute_sets(n, state, false)
|
1649
|
+
elsif at_mod?
|
1650
|
+
execute_args(n, nil, state, false)
|
1651
|
+
elsif colon_mod?
|
1652
|
+
execute_sets(n, state, true)
|
1653
|
+
else
|
1654
|
+
execute_args(n, state.next_arg, state, true)
|
1655
|
+
end
|
1656
|
+
end
|
1657
|
+
|
1658
|
+
# Connect a set of directives to this iteration directive.
|
1659
|
+
def connect(directives)
|
1660
|
+
directives.pop
|
1661
|
+
@directives = directives
|
1662
|
+
end
|
1663
|
+
|
1664
|
+
private
|
1665
|
+
|
1666
|
+
# Execute the iteration using sub-lists either from the following
|
1667
|
+
# argument or from the remaining arguments.
|
1668
|
+
def execute_sets(n, state, use_next_arg)
|
1669
|
+
if use_next_arg
|
1670
|
+
sets = state.next_arg
|
1671
|
+
arg_error 'argument not an array' unless sets.is_a? Array
|
1672
|
+
sets = sets[0...n] unless n.nil?
|
1673
|
+
else
|
1674
|
+
m = n
|
1675
|
+
sets = []
|
1676
|
+
while state.args_left > 0 and (m.nil? or m > 0)
|
1677
|
+
sets << state.next_arg
|
1678
|
+
m -= 1 unless m.nil?
|
1679
|
+
end
|
1680
|
+
end
|
1681
|
+
sets.each do |set|
|
1682
|
+
execute_args(nil, set, state, true)
|
1683
|
+
end
|
1684
|
+
end
|
1685
|
+
|
1686
|
+
# Execute the iteration while there are arguments left and we haven't
|
1687
|
+
# reached our limit of iterations.
|
1688
|
+
def execute_args(n, args, state, use_new_state)
|
1689
|
+
if use_new_state
|
1690
|
+
arg_error 'argument not an array' unless args.is_a? Array
|
1691
|
+
state = State.new(args, state.latest_output)
|
1692
|
+
end
|
1693
|
+
while state.args_left > 0 and (n.nil? or n > 0)
|
1694
|
+
Format.execute_directives(state, @directives)
|
1695
|
+
n -= 1 unless n.nil?
|
1696
|
+
end
|
1697
|
+
end
|
1698
|
+
end
|
1699
|
+
|
1700
|
+
# Represents the ~} (End iteration) directive. See BeginIteration for an
|
1701
|
+
# explanation of how these directives work together.
|
1702
|
+
class EndIteration < Directive
|
1703
|
+
# Raise a SyntaxError if +top+ is not a BeginIteration.
|
1704
|
+
def initialize(params, modifiers, top, pos)
|
1705
|
+
super params, modifiers, top, pos
|
1706
|
+
unless top.is_a? BeginIteration
|
1707
|
+
raise SynaxError, '~} without matching ~{'
|
1708
|
+
end
|
1709
|
+
end
|
1710
|
+
end
|
1711
|
+
|
1712
|
+
# Factory for directives. Formatting directives should be created using
|
1713
|
+
# singleton methods in this class.
|
1714
|
+
class Factory
|
1715
|
+
@@directives = {
|
1716
|
+
?A => [Ascii, 4, [], 0],
|
1717
|
+
?S => [SExpression, 4, [], 0],
|
1718
|
+
?D => [Decimal, 4, [], 0],
|
1719
|
+
?B => [Binary, 4, [], 0],
|
1720
|
+
?O => [Octal, 4, [], 0],
|
1721
|
+
?X => [Hexadecimal, 4, [], 0],
|
1722
|
+
?R => [Radix, 5, [], 0],
|
1723
|
+
?P => [Plural, 0, [], 0],
|
1724
|
+
?C => [Character, 0, [], 0],
|
1725
|
+
?F => [FFFP, 5, [?:], 0],
|
1726
|
+
?E => [ExpFP, 7, [?:], 0],
|
1727
|
+
?G => [GeneralFP, 7, [?:], 0],
|
1728
|
+
?$ => [DollarFP, 4, [], 0],
|
1729
|
+
?% => [NewLine, 1, [?:, ?@], 0],
|
1730
|
+
?& => [FreshLine, 1, [?:, ?@], 0],
|
1731
|
+
?| => [NewPage, 1, [?:, ?@], 0],
|
1732
|
+
?~ => [Tilde, 0, [?:, ?@], 0],
|
1733
|
+
?\n => [SkipWhitespace, 0, [[?:, ?@]], 0],
|
1734
|
+
?T => [Tabulate, 2, [], 0],
|
1735
|
+
?* => [ArgJump, 1, [[?:, ?@]], 0],
|
1736
|
+
?? => [Indirection, 0, [?:], 0],
|
1737
|
+
?( => [BeginCaseConversion, 0, [], 0],
|
1738
|
+
?) => [EndCaseConversion, 0, [?:, ?@], 0],
|
1739
|
+
?[ => [BeginConditional, 1, [[?:, ?@]], 1],
|
1740
|
+
?; => [ClauseSeparator, 0, [?@], 0],
|
1741
|
+
?] => [EndConditional, 0, [?@], -1],
|
1742
|
+
?{ => [BeginIteration, 1, [], 1],
|
1743
|
+
?} => [EndIteration, 0, [?:, ?@], -1],
|
1744
|
+
}
|
1745
|
+
|
1746
|
+
# Create a directive given a set of paramaters, modifiers, the
|
1747
|
+
# character representing the directive, possible owning directive, and
|
1748
|
+
# position in the format string.
|
1749
|
+
def self.build(params, modifiers, directive, top, pos)
|
1750
|
+
@@directives.include? directive or
|
1751
|
+
raise UnknownDirectiveError.new(pos), 'unknown format directive'
|
1752
|
+
idx = directive.chr.upcase[0]
|
1753
|
+
params.size <= @@directives[idx][1] or
|
1754
|
+
raise ParameterError.new(pos),
|
1755
|
+
'too many parameters given, expected no more than ' +
|
1756
|
+
@@directives[idx][1].to_s
|
1757
|
+
@@directives[idx][2].each do |illegal|
|
1758
|
+
if illegal.is_a? Array and (modifiers == illegal or
|
1759
|
+
modifiers.reverse == illegal)
|
1760
|
+
raise ModifierError.new(pos),
|
1761
|
+
'cannot specify both : and @ modifiers'
|
1762
|
+
elsif modifiers.include? illegal
|
1763
|
+
raise ModifierError.new(pos),
|
1764
|
+
'cannot specify the ' + mod.chr + 'modifier'
|
1765
|
+
end
|
1766
|
+
end
|
1767
|
+
return [
|
1768
|
+
@@directives[idx][0].new(params, modifiers, top, pos),
|
1769
|
+
@@directives[idx][3]
|
1770
|
+
]
|
1771
|
+
end
|
1772
|
+
end #class Factory
|
1773
|
+
|
1774
|
+
end #module Directives
|
1775
|
+
|
1776
|
+
private
|
1777
|
+
|
1778
|
+
# Execute a set of directives in a given state.
|
1779
|
+
def self.execute_directives(state, directives)
|
1780
|
+
directives.each do |directive|
|
1781
|
+
begin
|
1782
|
+
directive.execute state
|
1783
|
+
rescue => e
|
1784
|
+
e.pos = d.pos if e.respond_to?(:pos) and e.pos == -1
|
1785
|
+
raise
|
1786
|
+
end
|
1787
|
+
end
|
1788
|
+
end
|
1789
|
+
|
1790
|
+
end #module Format
|
1791
|
+
|
1792
|
+
def Lisp.format(format, *args)
|
1793
|
+
begin
|
1794
|
+
state = Format::State.new(args, Format::Output.new)
|
1795
|
+
formatter = Format::Formatter.new(format, state)
|
1796
|
+
formatter.run
|
1797
|
+
rescue => e
|
1798
|
+
puts 'Format error: ' + e.message
|
1799
|
+
puts format
|
1800
|
+
puts ' ' * (e.pos - 1) + '^' if e.respond_to? :pos
|
1801
|
+
raise
|
1802
|
+
end
|
1803
|
+
end
|
1804
|
+
|
1805
|
+
def format(format, *args)
|
1806
|
+
Lisp.format(format, *args)
|
1807
|
+
end
|
1808
|
+
|
1809
|
+
end #module Lisp
|
1810
|
+
|
1811
|
+
|
1812
|
+
|
1813
|
+
# _____ _
|
1814
|
+
# |_ _|__ ___| |_
|
1815
|
+
# | |/ _ \/ __| __|
|
1816
|
+
# | | __/\__ \ |_
|
1817
|
+
# |_|\___||___/\__|
|
1818
|
+
#
|
1819
|
+
|
1820
|
+
=begin test
|
1821
|
+
|
1822
|
+
require 'test/unit'
|
1823
|
+
|
1824
|
+
class FormatTest < Test::Unit::TestCase
|
1825
|
+
|
1826
|
+
def test_decimal
|
1827
|
+
assert( Lisp.format("~D", 1) == "1" )
|
1828
|
+
end
|
1829
|
+
|
1830
|
+
def test_decimal_params
|
1831
|
+
assert( Lisp.format("~5,'-D~6D", 1, 2) == "----1 2" )
|
1832
|
+
end
|
1833
|
+
|
1834
|
+
def test_decimal_modifiers
|
1835
|
+
assert( Lisp.format("~5,'-,'.:@D~@D", 1013, 2) == "+1.013+2" )
|
1836
|
+
assert( Lisp.format("~7,,,2:@D~@D", 1013, 2) == " +10,13+2" )
|
1837
|
+
end
|
1838
|
+
|
1839
|
+
# Tests for ~v, ~V, ~#
|
1840
|
+
|
1841
|
+
end
|
1842
|
+
|
1843
|
+
=end
|