dec_number 0.1.6 → 0.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/README CHANGED
@@ -1,20 +1,14 @@
1
- WARNING! Pre-release, not finished.
2
-
3
1
  DecNumber is a wrapper around ICU-decNumber (Copyright (c) IBM Corporation)
4
2
  that subclasses Numeric.
5
3
 
6
4
  The main benefit over BigDecimal and other things is that each instance carries it's own context around with it in a DecContext object. The context is what dertimines the precision and rounding behavior.
7
5
 
8
- An example of this in use might be a gas station where there are pump prices with 10ths of cents and store prices with only cents. The register sets a precision of 2 rounding up, and it can use the prices reported from the pump without incident.
9
-
10
- Another example is a database with Decimal columns with differing precision and where you can't accept using Floats.
11
-
12
- Another use case would be bitcoin, where you need an arbitrary precision, mixed with dollars.
6
+ An example is a database with Decimal columns with differing precision and where you can't accept using Floats.
13
7
 
14
8
  I don't expect to instantiate these object directly, instead I will bind them to SQL Decimal in an ORM, or using some sort of Money class.
15
9
 
16
10
  If you'd like to help out, please write tests!
17
11
 
18
- Currently they are not very good citizens of the Numeric family and try to give you back DecNumber objects whenever used. This is intentional. It might be a better idea in a Money class than returned from a db, however.
12
+ Currently they try to give you back DecNumber objects whenever used, including as the rval with another Numeric.
19
13
 
20
14
  TODO: Most of the methods should accept a context as an argument. Currently the context is attached to the receiver.
data/dec_number.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s| # -*-ruby-*-
2
2
  s.name = "dec_number"
3
- s.version = '0.1.6'
3
+ s.version = '0.2.0'
4
4
  s.authors = ["Paris Sinclair"]
5
5
  s.email = ["paris@rubypanther.com"]
6
6
  s.summary = "ICU-decNumber wrapper for arbitrary precision math with context objects"
@@ -1,5 +1,6 @@
1
1
  #include "ruby.h"
2
2
  #define DECNUMDIGITS 34
3
+ #define DECSUBSET 0
3
4
  #include "decNumber.h"
4
5
  #include <stdio.h>
5
6
 
@@ -54,6 +55,9 @@ VALUE cDecContext;
54
55
  result = rb_funcall( cDecNumber, rb_intern("new"), 0 ); \
55
56
  Data_Get_Struct(result, decNumber, result_ptr)
56
57
 
58
+ /*****
59
+ DecContext
60
+ *****/
57
61
  static VALUE con_alloc(VALUE klass) {
58
62
  decContext self_struct, *self_ptr;
59
63
  VALUE self;
@@ -62,21 +66,108 @@ static VALUE con_alloc(VALUE klass) {
62
66
  return self;
63
67
  }
64
68
 
69
+ static VALUE con_set_digits(VALUE self, VALUE new_value) {
70
+ decContext *self_ptr;
71
+ Data_Get_Struct(self, decContext, self_ptr);
72
+ self_ptr->digits = FIX2INT(new_value);
73
+ return INT2FIX(self_ptr->digits);
74
+ }
75
+
65
76
  static VALUE con_initialize(int argc, VALUE *argv, VALUE self) {
66
77
  decContext *self_ptr;
67
- VALUE from;
68
- rb_scan_args( argc, argv, "01", &from );
78
+ VALUE digits;
79
+ rb_scan_args( argc, argv, "01", &digits );
69
80
 
70
81
  Data_Get_Struct(self, decContext, self_ptr);
71
82
  decContextDefault(self_ptr, DEC_INIT_BASE);
72
83
  self_ptr->traps = 0; // no traps TODO: error handling
73
- self_ptr->digits = DECNUMDIGITS;
84
+
85
+ if ( NIL_P(digits) ) {
86
+ self_ptr->digits = DECNUMDIGITS;
87
+ } else {
88
+ con_set_digits(self,digits);
89
+ }
74
90
 
75
91
  // TODO: Handle arguments
76
92
 
77
93
  return self;
78
94
  }
79
95
 
96
+ static VALUE con_get_rounding(VALUE self) {
97
+ decContext *self_ptr;
98
+ enum rounding round;
99
+ VALUE name_sym, rounding_names;
100
+ Data_Get_Struct(self, decContext, self_ptr);
101
+ round = decContextGetRounding(self_ptr);
102
+ rounding_names = rb_const_get( cDecContext, rb_intern("ROUNDING_NAMES") );
103
+ name_sym = rb_hash_aref( rounding_names, INT2FIX(round) );
104
+ return name_sym;
105
+ }
106
+
107
+ static VALUE con_set_rounding(VALUE self, VALUE new_rounding) {
108
+ decContext *self_ptr;
109
+ enum rounding round;
110
+ VALUE rounding_numbers;
111
+
112
+ Data_Get_Struct(self, decContext, self_ptr);
113
+
114
+ if ( SYMBOL_P( new_rounding ) ) {
115
+ rounding_numbers = rb_const_get( cDecContext, rb_intern("ROUNDING_NUMBERS") );
116
+ new_rounding = rb_hash_aref( rounding_numbers, new_rounding );
117
+ }
118
+ if( ! FIXNUM_P( new_rounding ) ) {
119
+ rb_raise(rb_eTypeError, "wrong argument type");
120
+ }
121
+
122
+ round = FIX2INT(new_rounding);
123
+ decContextSetRounding(self_ptr,round);
124
+ return new_rounding;
125
+ }
126
+
127
+ static VALUE con_get_digits(VALUE self) {
128
+ decContext *self_ptr;
129
+ int digits;
130
+ VALUE r_fixnum;
131
+
132
+ Data_Get_Struct(self, decContext, self_ptr);
133
+ digits = self_ptr->digits;
134
+ r_fixnum = INT2FIX(digits);
135
+
136
+ return r_fixnum;
137
+ }
138
+
139
+ static VALUE con_get_emin(VALUE self) {
140
+ decContext *self_ptr;
141
+ Data_Get_Struct(self, decContext, self_ptr);
142
+ return INT2FIX(self_ptr->emin);
143
+ }
144
+
145
+ static VALUE con_set_emin(VALUE self, VALUE new_value) {
146
+ decContext *self_ptr;
147
+ Data_Get_Struct(self, decContext, self_ptr);
148
+ self_ptr->emin = FIX2INT(new_value);
149
+ return INT2FIX(self_ptr->emin);
150
+ }
151
+
152
+ static VALUE con_get_emax(VALUE self) {
153
+ decContext *self_ptr;
154
+ Data_Get_Struct(self, decContext, self_ptr);
155
+ return INT2FIX(self_ptr->emax);
156
+ }
157
+
158
+ static VALUE con_set_emax(VALUE self, VALUE new_value) {
159
+ decContext *self_ptr;
160
+ Data_Get_Struct(self, decContext, self_ptr);
161
+ self_ptr->emax = FIX2INT(new_value);
162
+ return INT2FIX(self_ptr->emax);
163
+ }
164
+ // /DecContext
165
+
166
+
167
+ /*****
168
+ DecNumber
169
+ *****/
170
+
80
171
  static VALUE num_alloc(VALUE klass) {
81
172
  decNumber self_struct, *self_ptr;
82
173
  decContext context;
@@ -92,10 +183,10 @@ static VALUE num_alloc(VALUE klass) {
92
183
  static VALUE num_initialize(int argc, VALUE *argv, VALUE self) {
93
184
  decNumber *self_ptr;
94
185
  decContext *context_ptr;
95
- VALUE from, r_str, context;
186
+ VALUE from, r_str, context, digits;
96
187
 
97
- rb_scan_args( argc, argv, "01", &from );
98
- context = rb_funcall( cDecContext, rb_intern("new"), 0 );
188
+ rb_scan_args( argc, argv, "02", &from, &digits );
189
+ context = rb_funcall( cDecContext, rb_intern("new"), 1, digits );
99
190
  rb_iv_set( self, "@context", context );
100
191
  Data_Get_Struct(context, decContext, context_ptr);
101
192
  Data_Get_Struct(self, decNumber, self_ptr);
@@ -447,12 +538,69 @@ static VALUE num_power(VALUE self, VALUE rval) {
447
538
  return result;
448
539
  }
449
540
 
541
+ void con_setup_rounding_constant( VALUE rounding_names, VALUE rounding_numbers, const char *sym_name, const char *const_name, enum rounding round ) {
542
+ VALUE round_num, round_sym;
543
+ round_num = INT2FIX(round);
544
+ round_sym = ID2SYM(rb_intern(sym_name));
545
+ rb_define_const( cDecContext, const_name, round_num );
546
+ rb_hash_aset( rounding_names, round_num, round_sym );
547
+ rb_hash_aset( rounding_numbers, round_sym, round_num );
548
+ return;
549
+ }
550
+
450
551
  void Init_dec_number() {
552
+ /****
553
+ DecContext
554
+ ****/
555
+
556
+ // *** constants and enums
557
+ enum rounding round;
558
+ VALUE rounding_names, rounding_numbers, round_default_num;
451
559
  cDecContext = rb_define_class("DecContext", rb_cObject);
560
+ rounding_names = rb_hash_new();
561
+ rb_define_const( cDecContext, "ROUNDING_NAMES", rounding_names );
562
+ rounding_numbers = rb_hash_new();
563
+ rb_define_const( cDecContext, "ROUNDING_NUMBERS", rounding_numbers );
564
+ con_setup_rounding_constant( rounding_names, rounding_numbers,
565
+ "ceil", "ROUND_CEIL", DEC_ROUND_CEILING );
566
+ con_setup_rounding_constant( rounding_names, rounding_numbers,
567
+ "down", "ROUND_DOWN", DEC_ROUND_DOWN );
568
+ con_setup_rounding_constant( rounding_names, rounding_numbers,
569
+ "floor", "ROUND_FLOOR", DEC_ROUND_FLOOR );
570
+ con_setup_rounding_constant( rounding_names, rounding_numbers,
571
+ "half_down", "ROUND_HALF_DOWN", DEC_ROUND_HALF_DOWN );
572
+ con_setup_rounding_constant( rounding_names, rounding_numbers,
573
+ "half_even", "ROUND_HALF_EVEN", DEC_ROUND_HALF_EVEN );
574
+ con_setup_rounding_constant( rounding_names, rounding_numbers,
575
+ "half_up", "ROUND_HALF_UP", DEC_ROUND_HALF_UP );
576
+ con_setup_rounding_constant( rounding_names, rounding_numbers,
577
+ "up", "ROUND_UP", DEC_ROUND_UP );
578
+ con_setup_rounding_constant( rounding_names, rounding_numbers,
579
+ "up05", "ROUND_05UP", DEC_ROUND_05UP );
580
+ // DEC_ROUND_DEFAULT is a macro with an extra ; so be careful
581
+ round = DEC_ROUND_DEFAULT;
582
+ round_default_num = INT2FIX(round);
583
+ rb_hash_aset( rounding_numbers, ID2SYM(rb_intern("default")), round_default_num );
584
+ rb_define_const( cDecContext, "ROUND_DEFAULT", round_default_num );
585
+
586
+ // *** methods
452
587
  rb_define_alloc_func(cDecContext, con_alloc);
453
588
  rb_define_method(cDecContext, "initialize", con_initialize, -1);
589
+ rb_define_method(cDecContext, "rounding", con_get_rounding, 0);
590
+ rb_define_method(cDecContext, "rounding=", con_set_rounding, 1);
591
+ rb_define_method(cDecContext, "digits", con_get_digits, 0);
592
+ rb_define_method(cDecContext, "digits=", con_set_digits, 1);
593
+ rb_define_method(cDecContext, "emin", con_get_emin, 0);
594
+ rb_define_method(cDecContext, "emin=", con_set_emin, 1);
595
+ rb_define_method(cDecContext, "emax", con_get_emax, 0);
596
+ rb_define_method(cDecContext, "emax=", con_set_emax, 1);
597
+
598
+ /****
599
+ DecNumber
600
+ ****/
454
601
  cDecNumber = rb_define_class("DecNumber", rb_cNumeric );
455
602
  rb_define_alloc_func(cDecNumber, num_alloc);
603
+ rb_define_attr( cDecNumber, "context", 1, 1);
456
604
  rb_define_method(cDecNumber, "initialize", num_initialize, -1);
457
605
  rb_define_method(cDecNumber, "to_s", num_to_s, 0);
458
606
  rb_define_method(cDecNumber, "to_i", num_to_i, 0);
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dec_number
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-17 00:00:00.000000000 Z
12
+ date: 2011-11-21 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Wrapper for ICU-decNumber library
15
15
  email: