ruby-fizzbuzz 0.0.2

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.
@@ -0,0 +1,233 @@
1
+ /* :enddoc: */
2
+
3
+ /*
4
+ * fizzbuzz.h
5
+ *
6
+ * Copyright 2012-2013 Krzysztof Wilczynski
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ */
20
+
21
+ #if !defined(_FIZZBUZZ_H)
22
+ #define _FIZZBUZZ_H 1
23
+
24
+ #include "common.h"
25
+
26
+ #if defined(__cplusplus)
27
+ extern "C" {
28
+ #endif
29
+
30
+ #define ZERO INT2FIX(0)
31
+ #define ONE INT2FIX(1)
32
+ #define THREE INT2FIX(3)
33
+ #define FIVE INT2FIX(5)
34
+
35
+ #define PLUS(a, b) fizzbuzz_plus((a), (b))
36
+ #define MINUS(a, b) fizzbuzz_minus((a), (b))
37
+ #define MOD(a, b) fizzbuzz_modulo((a), (b))
38
+
39
+ #define GREATER(a, b) fizzbuzz_greater((a), (b))
40
+ #define GREATER_EQUAL(a, b) fizzbuzz_greater_equal((a), (b))
41
+ #define LESS_EQUAL(a, b) fizzbuzz_less_equal((a), (b))
42
+
43
+ #define INTEGER_P(x) (TYPE(x) == T_FIXNUM || TYPE(x) == T_BIGNUM)
44
+
45
+ #define ZERO_P(x) \
46
+ (FIXNUM_P(x) ? (NUM2TYPE(x) == 0) : fizzbuzz_equal((x), ZERO))
47
+
48
+ #define INCREASE(x) PLUS((x), ONE)
49
+ #define DECREASE(x) MINUS((x), ONE)
50
+
51
+ #define COMPUTE_MOD_3(x) ZERO_P(MOD((x), THREE))
52
+ #define COMPUTE_MOD_5(x) ZERO_P(MOD((x), FIVE))
53
+
54
+ #define SCORE_FIXNUM(x) (uint8_t)(!((x) % 3) + 2 * !((x) % 5))
55
+ #define SCORE_BIGNUM(x) (uint8_t)(COMPUTE_MOD_3(x) + 2 * COMPUTE_MOD_5(x))
56
+
57
+ #define SCORE_VALUE(x) \
58
+ (FIXNUM_P(x) ? SCORE_FIXNUM(NUM2TYPE(x)) : SCORE_BIGNUM(x))
59
+
60
+ #define IS_FIZZ(x) (!ZERO_P(x) && (SCORE_VALUE(x) == 1))
61
+ #define IS_BUZZ(x) (!ZERO_P(x) && (SCORE_VALUE(x) == 2))
62
+ #define IS_FIZZBUZZ(x) (!ZERO_P(x) && (SCORE_VALUE(x) == 3))
63
+
64
+ #define WANT_ARRAY(x) ((x) == R_TYPE_ARRAY)
65
+
66
+ #define LOOP_FORWARD(x) ((x) == D_LOOP_FORWARD)
67
+ #define LOOP_REVERSE(x) ((x) == D_LOOP_REVERSE)
68
+
69
+ #define CHECK_TYPE(x, m) \
70
+ do { \
71
+ if (!INTEGER_P(x)) \
72
+ rb_raise(rb_eTypeError, "%s", (m)); \
73
+ } while (0)
74
+
75
+ #define CHECK_BOUNDARY(a, b, m) \
76
+ do { \
77
+ if (GREATER((a), (b))) \
78
+ rb_raise(rb_eArgError, "%s", (m)); \
79
+ } while (0)
80
+
81
+ enum error {
82
+ E_INVALID_TYPE = 0,
83
+ E_INVALID_START_TYPE,
84
+ E_INVALID_STOP_TYPE,
85
+ E_BAD_VALUE_START,
86
+ E_BAD_VALUE_STOP
87
+ };
88
+
89
+ enum return_type {
90
+ R_TYPE_ARRAY = 0,
91
+ R_TYPE_ENUMERATOR
92
+ };
93
+
94
+ enum direction {
95
+ D_LOOP_FORWARD = 0,
96
+ D_LOOP_REVERSE
97
+ };
98
+
99
+ typedef enum error error_t;
100
+ typedef enum return_type return_type_t;
101
+ typedef enum direction direction_t;
102
+
103
+ static const char *errors[] = {
104
+ "must be an integer value",
105
+ "must be an integer value for start",
106
+ "must be an integer value for stop",
107
+ "start value is higher than stop value",
108
+ "stop value is lower than start value",
109
+ NULL
110
+ };
111
+
112
+ static const char *words[] = {
113
+ "Fizz", "Buzz",
114
+ "FizzBuzz", NULL
115
+ };
116
+
117
+ inline static VALUE
118
+ fizzbuzz_plus(VALUE a, VALUE b)
119
+ {
120
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
121
+ return TYPE2NUM(NUM2TYPE(a) + NUM2TYPE(b));
122
+ }
123
+
124
+ return rb_funcall(a, rb_intern("+"), 1, b);
125
+ }
126
+
127
+ inline static VALUE
128
+ fizzbuzz_minus(VALUE a, VALUE b)
129
+ {
130
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
131
+ return TYPE2NUM(NUM2TYPE(a) - NUM2TYPE(b));
132
+ }
133
+
134
+ return rb_funcall(a, rb_intern("-"), 1, b);
135
+ }
136
+
137
+ inline static VALUE
138
+ fizzbuzz_modulo(VALUE a, VALUE b)
139
+ {
140
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
141
+ return TYPE2NUM(NUM2TYPE(a) % NUM2TYPE(b));
142
+ }
143
+
144
+ return rb_funcall(a, rb_intern("%"), 1, b);
145
+ }
146
+
147
+ inline static VALUE
148
+ fizzbuzz_equal(VALUE a, VALUE b)
149
+ {
150
+ VALUE result;
151
+
152
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
153
+ result = (NUM2TYPE(a) == NUM2TYPE(b));
154
+ }
155
+ else {
156
+ result = rb_funcall(a, rb_intern("=="), 1, b);
157
+ }
158
+
159
+ return RVAL2CBOOL(result);
160
+ }
161
+
162
+ inline static VALUE
163
+ fizzbuzz_greater(VALUE a, VALUE b)
164
+ {
165
+ VALUE result;
166
+
167
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
168
+ result = (NUM2TYPE(a) > NUM2TYPE(b));
169
+ }
170
+ else {
171
+ result = rb_funcall(a, rb_intern(">"), 1, b);
172
+ }
173
+
174
+ return RVAL2CBOOL(result);
175
+ }
176
+
177
+ inline static VALUE
178
+ fizzbuzz_greater_equal(VALUE a, VALUE b)
179
+ {
180
+ VALUE result;
181
+
182
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
183
+ result = (NUM2TYPE(a) >= NUM2TYPE(b));
184
+ }
185
+ else {
186
+ result = rb_funcall(a, rb_intern(">="), 1, b);
187
+ }
188
+
189
+ return RVAL2CBOOL(result);
190
+ }
191
+
192
+ inline static VALUE
193
+ fizzbuzz_less_equal(VALUE a, VALUE b)
194
+ {
195
+ VALUE result;
196
+
197
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
198
+ result = (NUM2TYPE(a) <= NUM2TYPE(b));
199
+ }
200
+ else {
201
+ result = rb_funcall(a, rb_intern("<="), 1, b);
202
+ }
203
+
204
+ return RVAL2CBOOL(result);
205
+ }
206
+
207
+ RUBY_EXTERN ID id_at_start, id_at_stop;
208
+ RUBY_EXTERN VALUE rb_cFizzBuzz;
209
+
210
+ RUBY_EXTERN VALUE rb_fb_initialize(int argc, VALUE *argv, VALUE object);
211
+
212
+ RUBY_EXTERN VALUE rb_fb_get_start(VALUE object);
213
+ RUBY_EXTERN VALUE rb_fb_set_start(VALUE object, VALUE value);
214
+ RUBY_EXTERN VALUE rb_fb_get_stop(VALUE object);
215
+ RUBY_EXTERN VALUE rb_fb_set_stop(VALUE object, VALUE value);
216
+
217
+ RUBY_EXTERN VALUE rb_fb_array(VALUE object);
218
+ RUBY_EXTERN VALUE rb_fb_enumerator(VALUE object);
219
+ RUBY_EXTERN VALUE rb_fb_reverse_enumerator(VALUE object);
220
+
221
+ RUBY_EXTERN VALUE rb_fb_is_fizz(VALUE object, VALUE value);
222
+ RUBY_EXTERN VALUE rb_fb_is_buzz(VALUE object, VALUE value);
223
+ RUBY_EXTERN VALUE rb_fb_is_fizzbuzz(VALUE object, VALUE value);
224
+
225
+ RUBY_EXTERN VALUE rb_fb_square(VALUE object, VALUE value);
226
+
227
+ #if defined(__cplusplus)
228
+ }
229
+ #endif
230
+
231
+ #endif /* _FIZZBUZZ_H */
232
+
233
+ /* vim: set ts=8 sw=4 sts=2 et : */
data/lib/fizzbuzz.rb ADDED
@@ -0,0 +1,94 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ # :stopdoc:
4
+
5
+ #
6
+ # fizzbuzz.rb
7
+ #
8
+ # Copyright 2012-2013 Krzysztof Wilczynski
9
+ #
10
+ # Licensed under the Apache License, Version 2.0 (the "License");
11
+ # you may not use this file except in compliance with the License.
12
+ # You may obtain a copy of the License at
13
+ #
14
+ # http://www.apache.org/licenses/LICENSE-2.0
15
+ #
16
+ # Unless required by applicable law or agreed to in writing, software
17
+ # distributed under the License is distributed on an "AS IS" BASIS,
18
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ # See the License for the specific language governing permissions and
20
+ # limitations under the License.
21
+ #
22
+
23
+ # :startdoc:
24
+
25
+ require 'fizzbuzz/fizzbuzz'
26
+ require 'fizzbuzz/version'
27
+ require 'fizzbuzz/integer'
28
+ require 'fizzbuzz/bignum'
29
+
30
+ #
31
+ # Yet another _FizzBuzz_ in Ruby.
32
+ #
33
+ # Provides simple and fast solution to a popular _FizzBuzz_ problem for Ruby.
34
+ #
35
+ class FizzBuzz
36
+ #
37
+ # call-seq:
38
+ # FizzBuzz.fizzbuzz( start, stop, reverse ) -> array
39
+ # FizzBuzz.fizzbuzz( start, stop, reverse ) {|value| block } -> self
40
+ #
41
+ # Returns either an array or accepts a block if such is given. When a block is given
42
+ # then it will call the block once for each subsequent value for a given range from
43
+ # +start+ to +stop+, passing the value as a parameter to the block.
44
+ #
45
+ # Additionally, if the value of +reverse+ is set to be +true+ then the results will
46
+ # be given in an <em>reverse order</em> whether in a resulting array or when passing
47
+ # values to a block given.
48
+ #
49
+ # Example:
50
+ #
51
+ # FizzBuzz.fizzbuzz(1, 15) #=> [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14, "FizzBuzz"]
52
+ # FizzBuzz.fizzbuzz(1, 15, true) #=> ["FizzBuzz", 14, 13, "Fizz", 11, "Buzz", "Fizz", 8, 7, "Fizz", "Buzz", 4, "Fizz", 2, 1]
53
+ #
54
+ # Example:
55
+ #
56
+ # FizzBuzz.fizzbuzz(1, 15) {|value| puts "Got #{value}" }
57
+ #
58
+ # Produces:
59
+ #
60
+ # Got 1
61
+ # Got 2
62
+ # Got Fizz
63
+ # Got 4
64
+ # Got Buzz
65
+ # Got Fizz
66
+ # Got 7
67
+ # Got 8
68
+ # Got Fizz
69
+ # Got Buzz
70
+ # Got 11
71
+ # Got Fizz
72
+ # Got 13
73
+ # Got 14
74
+ # Got FizzBuzz
75
+ #
76
+ # See also: FizzBuzz::[], FizzBuzz::new, FizzBuzz#to_a, FizzBuzz#each and FizzBuzz#reverse_each
77
+ #
78
+ def self.fizzbuzz(start, stop, reverse = false)
79
+ fb = FizzBuzz.new(start, stop)
80
+
81
+ if block_given?
82
+ fb.send(reverse ? :reverse_each : :each) {|i| yield i }
83
+ else
84
+ reverse ? fb.to_a.reverse : fb.to_a
85
+ end
86
+ end
87
+ end
88
+
89
+ # :enddoc:
90
+
91
+ FB = FizzBuzz
92
+
93
+ # vim: set ts=2 sw=2 sts=2 et :
94
+ # encoding: utf-8
@@ -0,0 +1,90 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ # :stopdoc:
4
+
5
+ #
6
+ # bignum.rb
7
+ #
8
+ # Copyright 2012-2013 Krzysztof Wilczynski
9
+ #
10
+ # Licensed under the Apache License, Version 2.0 (the "License");
11
+ # you may not use this file except in compliance with the License.
12
+ # You may obtain a copy of the License at
13
+ #
14
+ # http://www.apache.org/licenses/LICENSE-2.0
15
+ #
16
+ # Unless required by applicable law or agreed to in writing, software
17
+ # distributed under the License is distributed on an "AS IS" BASIS,
18
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ # See the License for the specific language governing permissions and
20
+ # limitations under the License.
21
+ #
22
+
23
+ # :startdoc:
24
+
25
+ #
26
+ # Provides a convenient integration of _FizzBuzz_ with _Bignum_ class.
27
+ #
28
+ class Bignum
29
+ #
30
+ # call-seq:
31
+ # Bignum.fizz? -> true or false
32
+ #
33
+ # Returns +true+ if a given integer value is divisible by *three* (given
34
+ # value is a _Fizz_), or +false+ otherwise.
35
+ #
36
+ # Example:
37
+ #
38
+ # 1000000000000.fizz? #=> false
39
+ # 1000000000002.fizz? #=> true
40
+ # 1000000000005.fizz? #=> false
41
+ #
42
+ # See also: FizzBuzz::[] and FizzBuzz::is_fizz?
43
+ #
44
+ def fizz?
45
+ FizzBuzz.is_fizz?(self)
46
+ end
47
+
48
+ #
49
+ # call-seq:
50
+ # Bignum.buzz? -> true or false
51
+ #
52
+ # Returns +true+ if a given integer value is divisible by *five* (given
53
+ # value is a _Buzz_), or +false+ otherwise.
54
+ #
55
+ # Example:
56
+ #
57
+ # 1000000000000.buzz? #=> true
58
+ # 1000000000002.buzz? #=> false
59
+ # 1000000000005.buzz? #=> false
60
+ #
61
+ # See also: FizzBuzz::[] and FizzBuzz::is_buzz?
62
+ #
63
+ def buzz?
64
+ FizzBuzz.is_buzz?(self)
65
+ end
66
+
67
+ #
68
+ # call-seq:
69
+ # Bignum.fizzbuzz? -> true or false
70
+ #
71
+ # Returns +true+ if a given integer value is divisible by both *three*
72
+ # and *five* (given value is a _FizzBuzz_), or +false+ otherwise.
73
+ #
74
+ # Example:
75
+ #
76
+ # 1000000000000.fizzbuzz? #=> false
77
+ # 1000000000002.fizzbuzz? #=> false
78
+ # 1000000000005.fizzbuzz? #=> true
79
+ #
80
+ # See also: FizzBuzz::[] and FizzBuzz::is_fizzbuzz?
81
+ #
82
+ def fizzbuzz?
83
+ FizzBuzz.is_fizzbuzz?(self)
84
+ end
85
+ end
86
+
87
+ # :enddoc:
88
+
89
+ # vim: set ts=2 sw=2 sts=2 et :
90
+ # encoding: utf-8
@@ -0,0 +1,90 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ # :stopdoc:
4
+
5
+ #
6
+ # integer.rb
7
+ #
8
+ # Copyright 2012 Krzysztof Wilczynski
9
+ #
10
+ # Licensed under the Apache License, Version 2.0 (the "License");
11
+ # you may not use this file except in compliance with the License.
12
+ # You may obtain a copy of the License at
13
+ #
14
+ # http://www.apache.org/licenses/LICENSE-2.0
15
+ #
16
+ # Unless required by applicable law or agreed to in writing, software
17
+ # distributed under the License is distributed on an "AS IS" BASIS,
18
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ # See the License for the specific language governing permissions and
20
+ # limitations under the License.
21
+ #
22
+
23
+ # :startdoc:
24
+
25
+ #
26
+ # Provides a convenient integration of _FizzBuzz_ with _Integer_ class.
27
+ #
28
+ class Integer
29
+ #
30
+ # call-seq:
31
+ # Integer.fizz? -> true or false
32
+ #
33
+ # Returns +true+ if a given integer value is divisible by *three* (given
34
+ # value is a _Fizz_), or +false+ otherwise.
35
+ #
36
+ # Example:
37
+ #
38
+ # 3.fizz? #=> true
39
+ # 5.fizz? #=> false
40
+ # 15.fizz? #=> false
41
+ #
42
+ # See also: FizzBuzz::[] and FizzBuzz::is_fizz?
43
+ #
44
+ def fizz?
45
+ FizzBuzz.is_fizz?(self)
46
+ end
47
+
48
+ #
49
+ # call-seq:
50
+ # Integer.buzz? -> true or false
51
+ #
52
+ # Returns +true+ if a given integer value is divisible by *five* (given
53
+ # value is a _Buzz_), or +false+ otherwise.
54
+ #
55
+ # Example:
56
+ #
57
+ # 3.buzz? #=> false
58
+ # 5.buzz? #=> true
59
+ # 15.buzz? #=> false
60
+ #
61
+ # See also: FizzBuzz::[] and FizzBuzz::is_buzz?
62
+ #
63
+ def buzz?
64
+ FizzBuzz.is_buzz?(self)
65
+ end
66
+
67
+ #
68
+ # call-seq:
69
+ # Integer.fizzbuzz? -> true or false
70
+ #
71
+ # Returns +true+ if a given integer value is divisible by both *three*
72
+ # and *five* (given value is a _FizzBuzz_), or +false+ otherwise.
73
+ #
74
+ # Example:
75
+ #
76
+ # 3.fizzbuzz? #=> false
77
+ # 5.fizzbuzz? #=> false
78
+ # 15.fizzbuzz? #=> true
79
+ #
80
+ # See also: FizzBuzz::[] and FizzBuzz::is_fizzbuzz?
81
+ #
82
+ def fizzbuzz?
83
+ FizzBuzz.is_fizzbuzz?(self)
84
+ end
85
+ end
86
+
87
+ # :enddoc:
88
+
89
+ # vim: set ts=2 sw=2 sts=2 et :
90
+ # encoding: utf-8