mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-encoding: add Poorman's Encoding gem
The difference from CRuby's Encoding: - Encoding is a module, instead of a class - each Encoding (e.g. `Encoding::UTF_8) is a string instead of Encoding object - only supports `UTF-8` and `ASCII-8BIT` (and its alias `BINARY`) Using this gem automatically turn on `MRB_UTF8_STRING` support.
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
MRuby::Gem::Specification.new('mruby-encoding') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.author = 'mruby developers'
|
||||
spec.summary = "Poorman's Encoding for mruby"
|
||||
spec.build.defines << "HAVE_MRUBY_ENCODING_GEM"
|
||||
spec.build.defines << "MRB_UTF8_STRING"
|
||||
spec.add_test_dependency 'mruby-string-ext'
|
||||
end
|
||||
@@ -0,0 +1,133 @@
|
||||
#include <mruby.h>
|
||||
#include <mruby/string.h>
|
||||
#include <mruby/variable.h>
|
||||
#include <mruby/internal.h>
|
||||
#include <mruby/presym.h>
|
||||
|
||||
#define ENC_ASCII_8BIT "ASCII-8BIT"
|
||||
#define ENC_BINARY "BINARY"
|
||||
#define ENC_UTF8 "UTF-8"
|
||||
|
||||
#define ENC_COMP_P(enc, enc_lit) \
|
||||
casecmp_p(RSTRING_PTR(enc), RSTRING_LEN(enc), enc_lit, sizeof(enc_lit"")-1)
|
||||
|
||||
static mrb_bool
|
||||
casecmp_p(const char *s1, mrb_int len1, const char *s2, mrb_int len2)
|
||||
{
|
||||
if (len1 != len2) return FALSE;
|
||||
|
||||
const char *e1 = s1 + len1;
|
||||
const char *e2 = s2 + len2;
|
||||
while (s1 < e1 && s2 < e2) {
|
||||
if (*s1 != *s2 && TOUPPER(*s1) != TOUPPER(*s2)) return FALSE;
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* string.valid_encoding? -> true or false
|
||||
*
|
||||
* Returns true for a string which is encoded correctly.
|
||||
*
|
||||
*/
|
||||
static mrb_value
|
||||
str_valid_enc_p(mrb_state *mrb, mrb_value str)
|
||||
{
|
||||
#define utf8_islead(c) ((unsigned char)((c)&0xc0) != 0x80)
|
||||
|
||||
struct RString *s = mrb_str_ptr(str);
|
||||
if (RSTR_SINGLE_BYTE_P(s)) return mrb_true_value();
|
||||
if (RSTR_BINARY_P(s)) return mrb_true_value();
|
||||
|
||||
mrb_int byte_len = RSTR_LEN(s);
|
||||
mrb_int utf8_len = 0;
|
||||
const char *p = RSTR_PTR(s);
|
||||
const char *e = p + byte_len;
|
||||
while (p < e) {
|
||||
mrb_int len = mrb_utf8len(p, e);
|
||||
|
||||
if (len == 1 && (*p & 0x80)) return mrb_false_value();
|
||||
p += len;
|
||||
utf8_len++;
|
||||
}
|
||||
if (byte_len == utf8_len) RSTR_SET_SINGLE_BYTE_FLAG(s);
|
||||
return mrb_true_value();
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
str_b(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_value str = mrb_str_dup(mrb, self);
|
||||
mrb_str_ptr(str)->flags |= MRB_STR_BINARY;
|
||||
return str;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
get_encoding(mrb_state *mrb, mrb_sym enc)
|
||||
{
|
||||
struct RClass *e = mrb_module_get_id(mrb, MRB_SYM(Encoding));
|
||||
return mrb_const_get(mrb, mrb_obj_value(e), enc);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
str_encoding(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
struct RString *s = mrb_str_ptr(self);
|
||||
if (RSTR_BINARY_P(s)) {
|
||||
return get_encoding(mrb, MRB_SYM(BINARY));
|
||||
}
|
||||
return get_encoding(mrb, MRB_SYM(UTF_8));
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
str_force_encoding(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_value enc;
|
||||
|
||||
mrb_get_args(mrb, "S", &enc);
|
||||
|
||||
struct RString *s = mrb_str_ptr(self);
|
||||
if (ENC_COMP_P(enc, ENC_ASCII_8BIT) ||
|
||||
ENC_COMP_P(enc, ENC_BINARY)) {
|
||||
s->flags |= MRB_STR_BINARY;
|
||||
}
|
||||
else if (ENC_COMP_P(enc, ENC_UTF8)) {
|
||||
s->flags &= ~MRB_STR_BINARY;
|
||||
}
|
||||
else {
|
||||
mrb_raisef(mrb, E_ARGUMENT_ERROR, "unknown encoding name - %v", enc);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
mrb_mruby_encoding_gem_init(mrb_state* mrb)
|
||||
{
|
||||
struct RClass *s = mrb->string_class;
|
||||
|
||||
mrb_define_method_id(mrb, s, MRB_SYM(b), str_b, MRB_ARGS_NONE());
|
||||
mrb_define_method_id(mrb, s, MRB_SYM_Q(valid_encoding), str_valid_enc_p, MRB_ARGS_NONE());
|
||||
mrb_define_method_id(mrb, s, MRB_SYM(encoding), str_encoding, MRB_ARGS_NONE());
|
||||
mrb_define_method_id(mrb, s, MRB_SYM(force_encoding), str_force_encoding, MRB_ARGS_REQ(1));
|
||||
|
||||
/* Poorman's Encoding
|
||||
*
|
||||
* Encoding - module instead of class
|
||||
* encodings - supports only UTF-8 and ASCII-8BIT (and its alias BINARY)
|
||||
* each Encoding - encoding name string instead of Encoding object
|
||||
*
|
||||
*/
|
||||
struct RClass *e = mrb_define_module_id(mrb, MRB_SYM(Encoding));
|
||||
mrb_value b = mrb_str_new_lit_frozen(mrb, ENC_ASCII_8BIT);
|
||||
mrb_define_const_id(mrb, e, MRB_SYM(ASCII_8BIT), b);
|
||||
mrb_define_const_id(mrb, e, MRB_SYM(BINARY), b);
|
||||
mrb_define_const_id(mrb, e, MRB_SYM(UTF_8), mrb_str_new_lit_frozen(mrb, ENC_UTF8));
|
||||
}
|
||||
|
||||
void
|
||||
mrb_mruby_encoding_gem_final(mrb_state* mrb)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
assert('Integer#chr') do
|
||||
assert_equal("A", 65.chr)
|
||||
assert_equal("B", 0x42.chr)
|
||||
assert_equal("\xab", 171.chr)
|
||||
assert_raise(RangeError) { -1.chr }
|
||||
assert_raise(RangeError) { 256.chr }
|
||||
|
||||
assert_equal("A", 65.chr("ASCII-8BIT"))
|
||||
assert_equal("B", 0x42.chr("BINARY"))
|
||||
assert_equal("\xab", 171.chr("ascii-8bit"))
|
||||
assert_raise(RangeError) { -1.chr("binary") }
|
||||
assert_raise(RangeError) { 256.chr("Ascii-8bit") }
|
||||
assert_raise(ArgumentError) { 65.chr("ASCII") }
|
||||
assert_raise(ArgumentError) { 65.chr("ASCII-8BIT", 2) }
|
||||
assert_raise(TypeError) { 65.chr(:BINARY) }
|
||||
|
||||
if __ENCODING__ == "ASCII-8BIT"
|
||||
assert_raise(ArgumentError) { 65.chr("UTF-8") }
|
||||
else
|
||||
assert_equal("A", 65.chr("UTF-8"))
|
||||
assert_equal("B", 0x42.chr("UTF-8"))
|
||||
assert_equal("«", 171.chr("utf-8"))
|
||||
assert_equal("あ", 12354.chr("Utf-8"))
|
||||
assert_raise(RangeError) { -1.chr("utf-8") }
|
||||
assert_raise(RangeError) { 0x110000.chr.chr("UTF-8") }
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,30 @@
|
||||
##
|
||||
# String(Ext) Test
|
||||
|
||||
UTF8STRING = __ENCODING__ == "UTF-8"
|
||||
|
||||
assert('String#valid_encoding?') do
|
||||
assert_true "hello".valid_encoding?
|
||||
if UTF8STRING
|
||||
assert_true "あ".valid_encoding?
|
||||
assert_false "\xfe".valid_encoding?
|
||||
assert_false "あ\xfe".valid_encoding?
|
||||
assert_true "あ\xfe".b.valid_encoding?
|
||||
else
|
||||
assert_true "\xfe".valid_encoding?
|
||||
end
|
||||
end
|
||||
|
||||
assert('String#encoding') do
|
||||
if UTF8STRING
|
||||
a = "あ"
|
||||
assert_equal Encoding::UTF_8, a.encoding
|
||||
assert_equal Encoding::BINARY, a.b.encoding
|
||||
assert_equal a, a.force_encoding(Encoding::BINARY)
|
||||
assert_equal a, a.force_encoding(Encoding::BINARY)
|
||||
assert_equal Encoding::BINARY, a.encoding
|
||||
else
|
||||
a = "hello"
|
||||
assert_equal Encoding::BINARY, a.encoding
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user