yard 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of yard might be problematic. Click here for more details.

Files changed (93) hide show
  1. data/ChangeLog +356 -0
  2. data/README.md +27 -5
  3. data/docs/GettingStarted.md +45 -6
  4. data/docs/Tags.md +16 -5
  5. data/docs/WhatsNew.md +60 -2
  6. data/lib/yard.rb +16 -37
  7. data/lib/yard/autoload.rb +5 -0
  8. data/lib/yard/cli/command.rb +18 -6
  9. data/lib/yard/cli/command_parser.rb +1 -0
  10. data/lib/yard/cli/config.rb +113 -0
  11. data/lib/yard/cli/gems.rb +16 -7
  12. data/lib/yard/cli/server.rb +30 -8
  13. data/lib/yard/cli/stats.rb +1 -1
  14. data/lib/yard/cli/yardoc.rb +16 -1
  15. data/lib/yard/code_objects/base.rb +7 -2
  16. data/lib/yard/code_objects/class_object.rb +1 -0
  17. data/lib/yard/code_objects/method_object.rb +1 -0
  18. data/lib/yard/code_objects/proxy.rb +8 -2
  19. data/lib/yard/config.rb +225 -0
  20. data/lib/yard/handlers/base.rb +29 -2
  21. data/lib/yard/handlers/processor.rb +1 -1
  22. data/lib/yard/handlers/ruby/class_handler.rb +6 -1
  23. data/lib/yard/handlers/ruby/constant_handler.rb +13 -15
  24. data/lib/yard/handlers/ruby/exception_handler.rb +1 -1
  25. data/lib/yard/handlers/ruby/extend_handler.rb +3 -0
  26. data/lib/yard/handlers/ruby/legacy/class_condition_handler.rb +1 -0
  27. data/lib/yard/handlers/ruby/legacy/class_handler.rb +7 -1
  28. data/lib/yard/handlers/ruby/legacy/constant_handler.rb +8 -10
  29. data/lib/yard/handlers/ruby/legacy/exception_handler.rb +1 -1
  30. data/lib/yard/handlers/ruby/legacy/extend_handler.rb +3 -0
  31. data/lib/yard/handlers/ruby/legacy/method_handler.rb +1 -0
  32. data/lib/yard/handlers/ruby/legacy/mixin_handler.rb +13 -2
  33. data/lib/yard/handlers/ruby/method_handler.rb +1 -0
  34. data/lib/yard/handlers/ruby/mixin_handler.rb +14 -4
  35. data/lib/yard/handlers/ruby/struct_handler_methods.rb +10 -1
  36. data/lib/yard/handlers/ruby/visibility_handler.rb +1 -1
  37. data/lib/yard/parser/c_parser.rb +26 -11
  38. data/lib/yard/parser/ruby/legacy/statement_list.rb +26 -9
  39. data/lib/yard/parser/source_parser.rb +5 -2
  40. data/lib/yard/serializers/yardoc_serializer.rb +2 -2
  41. data/lib/yard/server.rb +11 -0
  42. data/lib/yard/server/commands/frames_command.rb +1 -1
  43. data/lib/yard/server/commands/library_command.rb +22 -13
  44. data/lib/yard/server/commands/library_index_command.rb +1 -0
  45. data/lib/yard/server/commands/search_command.rb +2 -0
  46. data/lib/yard/server/commands/static_file_command.rb +6 -1
  47. data/lib/yard/server/templates/doc_server/processing/html/processing.erb +3 -3
  48. data/lib/yard/templates/helpers/html_helper.rb +1 -1
  49. data/lib/yard/templates/helpers/markup_helper.rb +13 -12
  50. data/lib/yard/verifier.rb +3 -1
  51. data/spec/cli/config_spec.rb +72 -0
  52. data/spec/cli/gems_spec.rb +81 -0
  53. data/spec/cli/server_spec.rb +35 -5
  54. data/spec/cli/stats_spec.rb +15 -0
  55. data/spec/cli/yardoc_spec.rb +39 -1
  56. data/spec/code_objects/base_spec.rb +2 -0
  57. data/spec/code_objects/method_object_spec.rb +5 -0
  58. data/spec/code_objects/proxy_spec.rb +20 -5
  59. data/spec/config_spec.rb +165 -0
  60. data/spec/handlers/alias_handler_spec.rb +7 -0
  61. data/spec/handlers/base_spec.rb +64 -0
  62. data/spec/handlers/class_condition_handler_spec.rb +13 -8
  63. data/spec/handlers/class_handler_spec.rb +54 -46
  64. data/spec/handlers/constant_handler_spec.rb +13 -0
  65. data/spec/handlers/examples/alias_handler_001.rb.txt +2 -0
  66. data/spec/handlers/examples/class_handler_001.rb.txt +12 -1
  67. data/spec/handlers/examples/constant_handler_001.rb.txt +6 -0
  68. data/spec/handlers/examples/exception_handler_001.rb.txt +8 -0
  69. data/spec/handlers/examples/method_handler_001.rb.txt +6 -0
  70. data/spec/handlers/examples/visibility_handler_001.rb.txt +3 -0
  71. data/spec/handlers/exception_handler_spec.rb +5 -0
  72. data/spec/handlers/extend_handler_spec.rb +4 -0
  73. data/spec/handlers/method_handler_spec.rb +5 -0
  74. data/spec/handlers/mixin_handler_spec.rb +10 -0
  75. data/spec/handlers/visibility_handler_spec.rb +4 -0
  76. data/spec/parser/base_spec.rb +1 -1
  77. data/spec/parser/c_parser_spec.rb +39 -1
  78. data/spec/parser/examples/override.c.txt +424 -0
  79. data/spec/parser/ruby/legacy/statement_list_spec.rb +11 -0
  80. data/spec/parser/source_parser_spec.rb +33 -1
  81. data/spec/server/commands/static_file_command_spec.rb +20 -3
  82. data/spec/server_spec.rb +10 -0
  83. data/spec/templates/examples/method001.html +33 -3
  84. data/spec/templates/examples/method001.txt +8 -1
  85. data/spec/templates/helpers/markup_helper_spec.rb +21 -26
  86. data/spec/templates/method_spec.rb +3 -1
  87. data/spec/verifier_spec.rb +5 -0
  88. data/templates/default/fulldoc/html/css/style.css +4 -1
  89. data/templates/default/fulldoc/html/js/app.js +1 -1
  90. data/templates/default/tags/html/option.erb +1 -3
  91. data/templates/default/tags/setup.rb +18 -15
  92. metadata +11 -4
  93. data/spec/yard_spec.rb +0 -55
@@ -8,6 +8,10 @@ describe "YARD::Handlers::Ruby::#{RUBY18 ? "Legacy::" : ""}ClassConditionHandler
8
8
  names.each {|name| Registry.at("A##{name}not").should be_nil }
9
9
  end
10
10
 
11
+ def no_undoc_error(code)
12
+ lambda { StubbedSourceParser.parse_string(code) }.should_not raise_error
13
+ end
14
+
11
15
  it "should parse all unless blocks for complex conditions" do
12
16
  verify_method :g
13
17
  end
@@ -45,13 +49,14 @@ describe "YARD::Handlers::Ruby::#{RUBY18 ? "Legacy::" : ""}ClassConditionHandler
45
49
  end
46
50
 
47
51
  it "should not fail on complex conditions" do
48
- lambda { YARD.parse_string("if defined?(A) && defined?(B); puts 'hi' end") }.should_not raise_error
49
- lambda do
50
- YARD.parse_string(<<-eof)
51
- (<<-TEST) unless defined?(ABCD_MODEL_TEST)
52
- 'String'
53
- TEST
54
- eof
55
- end.should_not raise_error
52
+ log.should_not_receive(:warn)
53
+ log.should_not_receive(:error)
54
+ no_undoc_error "if defined?(A) && defined?(B); puts 'hi' end"
55
+ no_undoc_error(<<-eof)
56
+ (<<-TEST) unless defined?(ABCD_MODEL_TEST)
57
+ 'String'
58
+ TEST
59
+ eof
60
+ no_undoc_error "if caller.none? { |l| l =~ %r{lib/rails/generators\\.rb:(\\d+):in `lookup!'$} }; end"
56
61
  end
57
62
  end
@@ -21,7 +21,7 @@ describe "YARD::Handlers::Ruby::#{RUBY18 ? "Legacy::" : ""}ClassHandler" do
21
21
  end
22
22
 
23
23
  it "should interpret class << ClassName as a class level block in ClassName's namespace" do
24
- P("A::B::C::Hello").should be_instance_of(CodeObjects::MethodObject)
24
+ P("A::B::C.Hello").should be_instance_of(CodeObjects::MethodObject)
25
25
  end
26
26
 
27
27
  it "should make visibility public when parsing a block" do
@@ -174,64 +174,72 @@ describe "YARD::Handlers::Ruby::#{RUBY18 ? "Legacy::" : ""}ClassHandler" do
174
174
  obj.tag(:param).types.should == ["IO"]
175
175
  end
176
176
 
177
- it "defines both readers and writers when @attr is used on Structs" do
178
- obj = Registry.at("SemiDoccedStruct")
179
- attrs = obj.attributes[:instance]
180
- attrs[:first][:read].should_not be_nil
181
- attrs[:first][:write].should_not be_nil
182
- end
177
+ ["SemiDoccedStruct", "NotAStruct"].each do |struct|
178
+ describe("Attributes on a " + (struct == "NotAStruct" ? "class" : "struct")) do
179
+ it "defines both readers and writers when @attr is used on Structs" do
180
+ obj = Registry.at(struct)
181
+ attrs = obj.attributes[:instance]
182
+ attrs[:first][:read].should_not be_nil
183
+ attrs[:first][:write].should_not be_nil
184
+ end
183
185
 
184
- it "defines only a reader when only @attr_reader is used on Structs" do
185
- obj = Registry.at("SemiDoccedStruct")
186
- attrs = obj.attributes[:instance]
187
- attrs[:second][:read].should_not be_nil
188
- attrs[:second][:write].should be_nil
189
- end
186
+ it "defines only a reader when only @attr_reader is used on Structs" do
187
+ obj = Registry.at(struct)
188
+ attrs = obj.attributes[:instance]
189
+ attrs[:second][:read].should_not be_nil
190
+ attrs[:second][:write].should be_nil
191
+ end
190
192
 
191
- it "defines only a writer when only @attr_writer is used on Structs" do
192
- obj = Registry.at("SemiDoccedStruct")
193
- attrs = obj.attributes[:instance]
194
- attrs[:third][:read].should be_nil
195
- attrs[:third][:write].should_not be_nil
196
- end
193
+ it "defines only a writer when only @attr_writer is used on Structs" do
194
+ obj = Registry.at(struct)
195
+ attrs = obj.attributes[:instance]
196
+ attrs[:third][:read].should be_nil
197
+ attrs[:third][:write].should_not be_nil
198
+ end
197
199
 
198
- it "defines a reader with correct return types when @attr_reader is used on Structs" do
199
- obj = Registry.at("SemiDoccedStruct#second")
200
- obj.tag(:return).types.should == ["Fixnum"]
201
- end
200
+ it "defines a reader with correct return types when @attr_reader is used on Structs" do
201
+ obj = Registry.at("#{struct}#second")
202
+ obj.tag(:return).types.should == ["Fixnum"]
203
+ end
202
204
 
203
- it "defines a writer with correct parameter types when @attr_writer is used on Structs" do
204
- obj = Registry.at("SemiDoccedStruct#third=")
205
- obj.tag(:param).types.should == ["Array"]
206
- end
205
+ it "defines a writer with correct parameter types when @attr_writer is used on Structs" do
206
+ obj = Registry.at("#{struct}#third=")
207
+ obj.tag(:param).types.should == ["Array"]
208
+ end
207
209
 
208
- it "defines a reader and a writer when both @attr_reader and @attr_writer are used" do
209
- obj = Registry.at("SemiDoccedStruct")
210
- attrs = obj.attributes[:instance]
211
- attrs[:fourth][:read].should_not be_nil
212
- attrs[:fourth][:write].should_not be_nil
213
- end
210
+ it "defines a reader and a writer when both @attr_reader and @attr_writer are used" do
211
+ obj = Registry.at(struct)
212
+ attrs = obj.attributes[:instance]
213
+ attrs[:fourth][:read].should_not be_nil
214
+ attrs[:fourth][:write].should_not be_nil
215
+ end
214
216
 
215
- it "uses @attr_reader for the getter when both @attr_reader and @attr_writer are given" do
216
- obj = Registry.at("SemiDoccedStruct#fourth")
217
- obj.tag(:return).types.should == ["#read"]
218
- end
217
+ it "uses @attr_reader for the getter when both @attr_reader and @attr_writer are given" do
218
+ obj = Registry.at("#{struct}#fourth")
219
+ obj.tag(:return).types.should == ["#read"]
220
+ end
219
221
 
220
- it "uses @attr_writer for the setter when both @attr_reader and @attr_writer are given" do
221
- obj = Registry.at("SemiDoccedStruct#fourth=")
222
- obj.tag(:param).types.should == ["IO"]
223
- end
222
+ it "uses @attr_writer for the setter when both @attr_reader and @attr_writer are given" do
223
+ obj = Registry.at("#{struct}#fourth=")
224
+ obj.tag(:param).types.should == ["IO"]
225
+ end
224
226
 
225
- it "extracts text from @attr_reader" do
226
- Registry.at("SemiDoccedStruct#fourth").docstring.should == "returns a proc that reads"
227
- end
227
+ it "extracts text from @attr_reader" do
228
+ Registry.at("#{struct}#fourth").docstring.should == "returns a proc that reads"
229
+ end
228
230
 
229
- it "extracts text from @attr_writer" do
230
- Registry.at("SemiDoccedStruct#fourth=").docstring.should == "sets the proc that writes stuff"
231
+ it "extracts text from @attr_writer" do
232
+ Registry.at("#{struct}#fourth=").docstring.should == "sets the proc that writes stuff"
233
+ end
234
+ end
231
235
  end
232
236
 
233
237
  it "should inherit from a regular struct" do
234
238
  Registry.at('RegularStruct').superclass.should == P(:Struct)
235
239
  Registry.at('RegularStruct2').superclass.should == P(:Struct)
236
240
  end
241
+
242
+ it "should handle inheritance from 'self'" do
243
+ Registry.at('Outer1::Inner1').superclass.should == Registry.at('Outer1')
244
+ end
237
245
  end
@@ -45,6 +45,19 @@ describe "YARD::Handlers::Ruby::#{RUBY18 ? "Legacy::" : ""}ConstantHandler" do
45
45
  obj.attributes[:instance].should be_empty
46
46
  end
47
47
 
48
+ it "should maintain docstrings on structs defined via constants" do
49
+ obj = Registry.at("DocstringStruct")
50
+ obj.should_not be_nil
51
+ obj.docstring.should == "A crazy struct."
52
+ obj.attributes[:instance].should_not be_empty
53
+ a1 = Registry.at("DocstringStruct#bar")
54
+ a2 = Registry.at("DocstringStruct#baz")
55
+ a1.docstring.should == "An attr"
56
+ a1.tag(:return).types.should == ["String"]
57
+ a2.docstring.should == "Another attr"
58
+ a2.tag(:return).types.should == ["Number"]
59
+ end
60
+
48
61
  it "should raise undocumentable error in 1.9 parser for Struct.new assignment to non-const" do
49
62
  undoc_error "nonconst = Struct.new"
50
63
  end if RUBY19
@@ -25,4 +25,6 @@ class B < C
25
25
  alias_method :t, :inspect if 500 == 3 * CONSTANT
26
26
  alias_method :<<, :a
27
27
  alias_method :for, :a
28
+ alias do x
29
+ alias x2 do
28
30
  end
@@ -105,4 +105,15 @@ end
105
105
  # @attr_reader [#read] fourth returns a proc that reads
106
106
  # @attr_writer [IO] fourth sets the proc that writes stuff
107
107
  class SemiDoccedStruct < Struct.new(:first, :second, :third, :fourth)
108
- end
108
+ end
109
+
110
+ # @attr [String] first the first entry
111
+ # @attr_reader [Fixnum] second this only has a reader
112
+ # @attr_writer [Array] third this only has a writer
113
+ # @attr_reader [#read] fourth returns a proc that reads
114
+ # @attr_writer [IO] fourth sets the proc that writes stuff
115
+ class NotAStruct; end
116
+
117
+ class Outer1
118
+ class Inner1 < self; end
119
+ end
@@ -17,3 +17,9 @@ end
17
17
  MyClass = Struct.new(:a, :b, :c)
18
18
  NotMyClass = Struct.new("NotMyClass2", :b, :c)
19
19
  MyEmptyStruct = Struct.new
20
+
21
+ # A crazy struct.
22
+ #
23
+ # @attr [String] bar An attr
24
+ # @attr [Number] baz Another attr
25
+ DocstringStruct = Struct.new(:bar, :baz)
@@ -44,4 +44,12 @@ class Testing
44
44
  obj.raise IgnoreMe
45
45
  obj.raise(IgnoreMe)
46
46
  end
47
+
48
+ def mymethod10
49
+ raise ArgumentError 'Message' # actually a method call
50
+ end
51
+
52
+ def mymethod11
53
+ raise foo('bar')
54
+ end
47
55
  end
@@ -79,3 +79,9 @@ end
79
79
  def auto_opts(opts)
80
80
  end
81
81
  end
82
+
83
+ CONST = Foo
84
+ def CONST.meth_on_const; end
85
+ CONST2 = CONST
86
+ def CONST2.meth2_on_const; end
87
+
@@ -21,4 +21,7 @@ class Testing
21
21
  private name
22
22
  private *argument
23
23
  private *(method_call)
24
+
25
+ def Foo; end
26
+ private :Foo
24
27
  end
@@ -36,4 +36,9 @@ describe "YARD::Handlers::Ruby::#{RUBY18 ? "Legacy::" : ""}ExceptionHandler" do
36
36
  it "should ignore any raise calls on a receiver" do
37
37
  P('Testing#mymethod9').tag(:raise).should be_nil
38
38
  end
39
+
40
+ it "should handle raise expressions that are method calls" do
41
+ P('Testing#mymethod10').tag(:raise).should be_nil
42
+ P('Testing#mymethod11').tag(:raise).should be_nil
43
+ end
39
44
  end
@@ -16,4 +16,8 @@ describe "YARD::Handlers::Ruby::#{RUBY18 ? "Legacy::" : ""}ExtendHandler" do
16
16
  it "should extend module with correct namespace" do
17
17
  Registry.at('Q::R::S').class_mixins.first.path.should == 'A'
18
18
  end
19
+
20
+ it "should not allow extending self if object is a class" do
21
+ undoc_error "class Foo; extend self; end"
22
+ end
19
23
  end
@@ -127,4 +127,9 @@ describe "YARD::Handlers::Ruby::#{RUBY18 ? "Legacy::" : ""}MethodHandler" do
127
127
  undoc_error "error = Foo; def error.at(foo) end"
128
128
  Registry.at('error').should be_nil
129
129
  end
130
+
131
+ it "should allow class method to be defined on constant reference object" do
132
+ Registry.at('Foo.meth_on_const').should_not be_nil
133
+ Registry.at('Foo.meth2_on_const').should_not be_nil
134
+ end
130
135
  end
@@ -37,4 +37,14 @@ describe "YARD::Handlers::Ruby::#{RUBY18 ? "Legacy::" : ""}MixinHandler" do
37
37
  P("ABC::DEF::FOO").mixins.should == [P("ABC::FOO")]
38
38
  P("ABC::DEF::BAR").mixins.should == [P("ABC::BAR")]
39
39
  end
40
+
41
+ it "should raise undocumentable error if argument is variable" do
42
+ undoc_error "module X; include invalid; end"
43
+ Registry.at('X').mixins.should == []
44
+ end
45
+
46
+ it "should parse all other arguments before erroring out on undocumentable error" do
47
+ undoc_error "module X; include invalid, Y; end"
48
+ Registry.at('X').mixins.should == [P('Y')]
49
+ end
40
50
  end
@@ -27,4 +27,8 @@ describe "YARD::Handlers::Ruby::#{RUBY18 ? "Legacy::" : ""}VisibilityHandler" do
27
27
  Registry.at('Testing#argument').should be_nil
28
28
  Registry.at('Testing#method_call').should be_nil
29
29
  end
30
+
31
+ it "should handle constants passed in as symbols" do
32
+ Registry.at('Testing#Foo').visibility.should == :private
33
+ end
30
34
  end
@@ -7,7 +7,7 @@ describe YARD::Parser::Base do
7
7
  end
8
8
 
9
9
  it "should take 2 arguments" do
10
- lambda { Parser::Base.new }.should raise_error(ArgumentError, /wrong number of arguments/)
10
+ lambda { Parser::Base.new }.should raise_error(ArgumentError, /wrong (number|#) of arguments/)
11
11
  end
12
12
 
13
13
  it "should raise NotImplementedError on #initialize" do
@@ -5,6 +5,9 @@ describe YARD::Parser::CParser do
5
5
  before(:all) do
6
6
  file = File.join(File.dirname(__FILE__), 'examples', 'array.c.txt')
7
7
  @parser = Parser::CParser.new(IO.read(file)).parse
8
+
9
+ override_file = File.join(File.dirname(__FILE__), 'examples', 'override.c.txt')
10
+ @override_parser = Parser::CParser.new(IO.read(override_file)).parse
8
11
  end
9
12
 
10
13
  describe '#parse' do
@@ -20,4 +23,39 @@ describe YARD::Parser::CParser do
20
23
  obj.tags(:overload).size.should > 1
21
24
  end
22
25
  end
23
- end
26
+
27
+ describe '#find_override_comment' do
28
+ it "should parse GMP::Z class" do
29
+ z = YARD::Registry.at('GMP::Z')
30
+ z.should_not be_nil
31
+ z.docstring.should_not be_blank
32
+ end
33
+
34
+ it "should parse GMP::Z methods w/ bodies" do
35
+ add = YARD::Registry.at('GMP::Z#+')
36
+ add.docstring.should_not be_blank
37
+ add.source.should_not be_nil
38
+ add.source.should_not be_empty
39
+
40
+ add_self = YARD::Registry.at('GMP::Z#+')
41
+ add_self.docstring.should_not be_blank
42
+ add_self.source.should_not be_nil
43
+ add_self.source.should_not be_empty
44
+
45
+ sqrtrem = YARD::Registry.at('GMP::Z#+')
46
+ sqrtrem.docstring.should_not be_blank
47
+ sqrtrem.source.should_not be_nil
48
+ sqrtrem.source.should_not be_empty
49
+ end
50
+
51
+ it "should parse GMP::Z methods w/o bodies" do
52
+ neg = YARD::Registry.at('GMP::Z#neg')
53
+ neg.docstring.should_not be_blank
54
+ neg.source.should be_nil
55
+
56
+ neg_self = YARD::Registry.at('GMP::Z#neg')
57
+ neg_self.docstring.should_not be_blank
58
+ neg_self.source.should be_nil
59
+ end
60
+ end
61
+ end if CONTINUATIONS_SUPPORTED
@@ -0,0 +1,424 @@
1
+ #include <gmpz.h>
2
+ #include <gmpq.h>
3
+ #include <gmpf.h>
4
+
5
+ /*
6
+ * Document-class: GMP::Z
7
+ *
8
+ * GMP Multiple Precision Integer.
9
+ *
10
+ * Instances of this class can store variables of the type mpz_t. This class
11
+ * also contains many methods that act as the functions for mpz_t variables,
12
+ * as well as a few methods that attempt to make this library more Ruby-ish.
13
+ */
14
+
15
+ /**********************************************************************
16
+ * Macros *
17
+ **********************************************************************/
18
+
19
+ /*
20
+ * DEFUN_INT2INT defines two functions. The first takes a GMP::Z as
21
+ * self, calls mpz_fname on the contained mpz_t, whose arguments are
22
+ * exactly (0) the return argument and (1) self. The second is the same
23
+ * destructive method.
24
+ */
25
+ #define DEFUN_INT2INT(fname,mpz_fname) \
26
+ static VALUE r_gmpz_##fname(VALUE self) \
27
+ { \
28
+ MP_INT *self_val, *res_val; \
29
+ VALUE res; \
30
+ mpz_get_struct(self, self_val); \
31
+ mpz_make_struct_init(res, res_val); \
32
+ mpz_fname(res_val, self_val); \
33
+ return res; \
34
+ } \
35
+ \
36
+ static VALUE r_gmpz_##fname##_self(VALUE self) \
37
+ { \
38
+ MP_INT *self_val; \
39
+ mpz_get_struct(self, self_val); \
40
+ mpz_fname(self_val, self_val); \
41
+ return self; \
42
+ }
43
+
44
+
45
+ /**********************************************************************
46
+ * Integer Arithmetic *
47
+ **********************************************************************/
48
+
49
+ /*
50
+ * call-seq:
51
+ * a + b
52
+ *
53
+ * Adds _a_ to _b_. _b_ must be an instance of one of:
54
+ * * GMP::Z
55
+ * * Fixnum
56
+ * * GMP::Q
57
+ * * GMP::F
58
+ * * Bignum
59
+ */
60
+ VALUE r_gmpz_add(VALUE self, VALUE arg)
61
+ {
62
+ MP_INT *self_val, *arg_val, *res_val;
63
+ VALUE res;
64
+
65
+ mpz_get_struct(self,self_val);
66
+
67
+ if (GMPZ_P(arg)) {
68
+ mpz_get_struct(arg,arg_val);
69
+ mpz_make_struct_init(res, res_val);
70
+ mpz_add(res_val, self_val, arg_val);
71
+ } else if (FIXNUM_P(arg)) {
72
+ mpz_make_struct_init(res, res_val);
73
+ if (FIX2NUM(arg) > 0)
74
+ mpz_add_ui(res_val, self_val, FIX2NUM(arg));
75
+ else
76
+ mpz_sub_ui(res_val, self_val, -FIX2NUM(arg));
77
+ } else if (GMPQ_P(arg)) {
78
+ return r_gmpq_add(arg, self);
79
+ } else if (GMPF_P(arg)) {
80
+ #ifndef MPFR
81
+ return r_gmpf_add(arg, self);
82
+ #else
83
+ return rb_funcall(arg, rb_intern("+"), 1, self);
84
+ #endif
85
+ } else if (BIGNUM_P(arg)) {
86
+ mpz_make_struct_init(res, res_val);
87
+ mpz_init(res_val);
88
+ mpz_set_bignum(res_val, arg);
89
+ mpz_add(res_val, res_val, self_val);
90
+ } else {
91
+ typeerror(ZQFXB);
92
+ }
93
+ return res;
94
+ }
95
+
96
+ /*
97
+ * call-seq:
98
+ * a.add!(_b_)
99
+ *
100
+ * Adds _a_ to _b_ in-place, setting _a_ to the sum. _b_ must be an instance of one of:
101
+ * * GMP::Z
102
+ * * Fixnum
103
+ * * GMP::Q
104
+ * * GMP::F
105
+ * * Bignum
106
+ */
107
+ VALUE r_gmpz_add_self(VALUE self, VALUE arg)
108
+ {
109
+ MP_INT *self_val, *arg_val;
110
+
111
+ mpz_get_struct(self,self_val);
112
+
113
+ if (GMPZ_P(arg)) {
114
+ mpz_get_struct(arg,arg_val);
115
+ mpz_add(self_val, self_val, arg_val);
116
+ } else if (FIXNUM_P(arg)) {
117
+ if (FIX2NUM(arg) > 0)
118
+ mpz_add_ui(self_val, self_val, FIX2NUM(arg));
119
+ else
120
+ mpz_sub_ui(self_val, self_val, -FIX2NUM(arg));
121
+ } else if (BIGNUM_P(arg)) {
122
+ mpz_temp_from_bignum(arg_val, arg);
123
+ mpz_add(self_val, self_val, arg_val);
124
+ mpz_temp_free(arg_val);
125
+ } else {
126
+ typeerror(ZXB);
127
+ }
128
+ return Qnil;
129
+ }
130
+
131
+ /*
132
+ * call-seq:
133
+ * a - b
134
+ *
135
+ * Subtracts _b_ from _a_. _b_ must be an instance of one of:
136
+ * * GMP::Z
137
+ * * Fixnum
138
+ * * GMP::Q
139
+ * * GMP::F
140
+ * * Bignum
141
+ */
142
+ VALUE r_gmpz_sub(VALUE self, VALUE arg)
143
+ {
144
+ MP_RAT *res_val_q, *arg_val_q;
145
+ MP_INT *self_val, *arg_val, *res_val;
146
+ MP_FLOAT *arg_val_f, *res_val_f;
147
+ VALUE res;
148
+ unsigned long prec;
149
+
150
+ mpz_get_struct(self,self_val);
151
+
152
+ if (GMPZ_P(arg)) {
153
+ mpz_make_struct_init(res, res_val);
154
+ mpz_get_struct(arg,arg_val);
155
+ mpz_sub (res_val, self_val, arg_val);
156
+ } else if (FIXNUM_P(arg)) {
157
+ mpz_make_struct_init(res, res_val);
158
+ if (FIX2NUM(arg) > 0)
159
+ mpz_sub_ui (res_val, self_val, FIX2NUM(arg));
160
+ else
161
+ mpz_add_ui (res_val, self_val, -FIX2NUM(arg));
162
+ } else if (GMPQ_P(arg)) {
163
+ mpq_make_struct_init(res, res_val_q);
164
+ mpq_get_struct(arg,arg_val_q);
165
+ mpz_set (mpq_denref(res_val_q), mpq_denref(arg_val_q));
166
+ mpz_mul (mpq_numref(res_val_q), mpq_denref(arg_val_q), self_val);
167
+ mpz_sub (mpq_numref(res_val_q), mpq_numref(res_val_q), mpq_numref(arg_val_q));
168
+ } else if (GMPF_P(arg)) {
169
+ mpf_get_struct_prec (arg, arg_val_f, prec);
170
+ mpf_make_struct_init(res, res_val_f, prec);
171
+ mpf_set_z (res_val_f, self_val);
172
+ mpf_sub (res_val_f, res_val_f, arg_val_f);
173
+ } else if (BIGNUM_P(arg)) {
174
+ mpz_make_struct_init(res, res_val);
175
+ mpz_set_bignum (res_val, arg);
176
+ mpz_sub (res_val, self_val, res_val);
177
+ } else {
178
+ typeerror (ZQFXB);
179
+ }
180
+ return res;
181
+ }
182
+
183
+ /*
184
+ * call-seq:
185
+ * a.sub!(b)
186
+ *
187
+ * Subtracts _b_ from _a_ in-place, setting _a_ to the difference. _b_ must be an
188
+ * instance of one of:
189
+ * * GMP::Z
190
+ * * Fixnum
191
+ * * GMP::Q
192
+ * * GMP::F
193
+ * * Bignum
194
+ */
195
+ VALUE r_gmpz_sub_self(VALUE self, VALUE arg)
196
+ {
197
+ MP_INT *self_val, *arg_val;
198
+
199
+ mpz_get_struct(self,self_val);
200
+
201
+ if (GMPZ_P(arg)) {
202
+ mpz_get_struct(arg, arg_val);
203
+ mpz_sub (self_val, self_val, arg_val);
204
+ } else if (FIXNUM_P(arg)) {
205
+ if (FIX2NUM(arg) > 0)
206
+ mpz_sub_ui (self_val, self_val, FIX2NUM(arg));
207
+ else
208
+ mpz_add_ui (self_val, self_val, -FIX2NUM(arg));
209
+ } else if (BIGNUM_P(arg)) {
210
+ mpz_temp_from_bignum(arg_val, arg);
211
+ mpz_sub (self_val, self_val, arg_val);
212
+ mpz_temp_free (arg_val);
213
+ } else {
214
+ typeerror (ZXB);
215
+ }
216
+ return Qnil;
217
+ }
218
+
219
+ /*
220
+ * call-seq:
221
+ * a * b
222
+ *
223
+ * Multiplies _a_ with _b_. _a_ must be an instance of one of
224
+ * * GMP::Z
225
+ * * Fixnum
226
+ * * GMP::Q
227
+ * * GMP::F
228
+ * * Bignum
229
+ */
230
+ VALUE r_gmpz_mul(VALUE self, VALUE arg)
231
+ {
232
+ MP_INT *self_val, *arg_val, *res_val;
233
+ VALUE res;
234
+
235
+ mpz_get_struct(self,self_val);
236
+
237
+ if (GMPZ_P(arg)) {
238
+ mpz_make_struct_init(res, res_val);
239
+ mpz_get_struct(arg,arg_val);
240
+ mpz_mul(res_val, self_val, arg_val);
241
+ } else if (FIXNUM_P(arg)) {
242
+ mpz_make_struct_init(res, res_val);
243
+ mpz_mul_si(res_val, self_val, FIX2NUM(arg));
244
+ } else if (GMPQ_P(arg)) {
245
+ return r_gmpq_mul(arg, self);
246
+ } else if (GMPF_P(arg)) {
247
+ #ifndef MPFR
248
+ return r_gmpf_mul(arg, self);
249
+ #else
250
+ return rb_funcall(arg, rb_intern("*"), 1, self);
251
+ #endif
252
+ } else if (BIGNUM_P(arg)) {
253
+ mpz_make_struct_init(res, res_val);
254
+ mpz_set_bignum(res_val, arg);
255
+ mpz_mul(res_val, res_val, self_val);
256
+ } else {
257
+ typeerror(ZQFXB);
258
+ }
259
+ return res;
260
+ }
261
+
262
+ /*
263
+ * call-seq:
264
+ * a.addmul!(b, c)
265
+ *
266
+ * @since 0.4.17
267
+ *
268
+ * Sets _a_ to _a_ plus _b_ times _c_. _b_ and _c_ must each be an instance of one of
269
+ * * GMP::Z
270
+ * * Fixnum
271
+ * * Bignum
272
+ */
273
+ VALUE r_gmpz_addmul_self(VALUE self, VALUE b, VALUE c)
274
+ {
275
+ MP_INT *self_val, *b_val, *c_val;
276
+ int free_b_val = 0;
277
+
278
+ if (GMPZ_P(b)) {
279
+ mpz_get_struct(b, b_val);
280
+ } else if (FIXNUM_P(b)) {
281
+ mpz_temp_alloc(b_val);
282
+ mpz_init_set_si(b_val, FIX2NUM(b));
283
+ free_b_val = 1;
284
+ } else if (BIGNUM_P(b)) {
285
+ mpz_temp_from_bignum(b_val, b);
286
+ free_b_val = 1;
287
+ } else {
288
+ typeerror_as(ZXB, "addend");
289
+ }
290
+ mpz_get_struct(self, self_val);
291
+
292
+ if (GMPZ_P(c)) {
293
+ mpz_get_struct(c, c_val);
294
+ mpz_addmul(self_val, b_val, c_val);
295
+ } else if (FIXNUM_P(c)) {
296
+ if (FIX2NUM(c) < 0)
297
+ {
298
+ if (free_b_val) { mpz_temp_free(b_val); }
299
+ rb_raise(rb_eRangeError, "multiplicand (Fixnum) must be nonnegative");
300
+ }
301
+ mpz_addmul_ui(self_val, b_val, FIX2NUM(c));
302
+ } else if (BIGNUM_P(c)) {
303
+ mpz_temp_from_bignum(c_val, c);
304
+ mpz_addmul(self_val, b_val, c_val);
305
+ mpz_temp_free(c_val);
306
+ } else {
307
+ if (free_b_val)
308
+ mpz_temp_free(b_val);
309
+ typeerror_as(ZXB, "multiplicand");
310
+ }
311
+ if (free_b_val)
312
+ mpz_temp_free(b_val);
313
+ return self;
314
+ }
315
+
316
+ /*
317
+ * Document-method: neg
318
+ *
319
+ * call-seq:
320
+ * a.neg
321
+ * -a
322
+ *
323
+ * Returns -_a_.
324
+ */
325
+ /*
326
+ * Document-method: neg!
327
+ *
328
+ * call-seq:
329
+ * a.neg!
330
+ *
331
+ * Sets _a_ to -_a_.
332
+ */
333
+ DEFUN_INT2INT(neg, mpz_neg)
334
+ /*
335
+ * Document-method: abs
336
+ *
337
+ * call-seq:
338
+ * a.abs
339
+ *
340
+ * Returns the absolute value of _a_.
341
+ */
342
+ /*
343
+ * Document-method: abs!
344
+ *
345
+ * call-seq:
346
+ * a.abs!
347
+ *
348
+ * Sets _a_ to its absolute value.
349
+ */
350
+ DEFUN_INT2INT(abs, mpz_abs)
351
+
352
+
353
+ /**********************************************************************
354
+ * Integer Roots *
355
+ **********************************************************************/
356
+
357
+ /*
358
+ * Document-method: sqrt
359
+ *
360
+ * call-seq:
361
+ * a.sqrt
362
+ *
363
+ * Returns the truncated integer part of the square root of _a_.
364
+ */
365
+ /*
366
+ * Document-method: sqrt!
367
+ *
368
+ * call-seq:
369
+ * a.sqrt!
370
+ *
371
+ * Sets _a_ to the truncated integer part of its square root.
372
+ */
373
+ DEFUN_INT2INT(sqrt, mpz_sqrt)
374
+
375
+ /*
376
+ * call-seq:
377
+ * a.sqrtrem #=> s, r
378
+ *
379
+ * Returns the truncated integer part of the square root of _a_ as _s_ and the remainder
380
+ * <i>a - s * s</i> as _r_, which will be zero if _a_ is a perfect square.
381
+ */
382
+ static VALUE r_gmpz_sqrtrem(VALUE self)
383
+ {
384
+ MP_INT *self_val, *sqrt_val, *rem_val;
385
+ VALUE sqrt, rem;
386
+
387
+ mpz_get_struct(self, self_val);
388
+ mpz_make_struct_init(sqrt, sqrt_val);
389
+ mpz_make_struct_init(rem, rem_val);
390
+ mpz_sqrtrem(sqrt_val, rem_val, self_val);
391
+ return rb_assoc_new(sqrt, rem);
392
+ }
393
+
394
+
395
+ /**********************************************************************
396
+ * Init function *
397
+ **********************************************************************/
398
+
399
+ void init_gmpz()
400
+ {
401
+ mGMP = rb_define_module("GMP");
402
+ rb_define_module_function(mGMP, "Z", r_gmpmod_z, -1);
403
+
404
+ cGMP_Z = rb_define_class_under(mGMP, "Z", rb_cInteger);
405
+
406
+ // Integer Arithmetic
407
+ rb_define_method(cGMP_Z, "+", r_gmpz_add, 1);
408
+ rb_define_method(cGMP_Z, "add!", r_gmpz_add_self, 1);
409
+ rb_define_method(cGMP_Z, "-", r_gmpz_sub, 1);
410
+ rb_define_method(cGMP_Z, "sub!", r_gmpz_sub_self, 1);
411
+ rb_define_method(cGMP_Z, "*", r_gmpz_mul, 1);
412
+ rb_define_method(cGMP_Z, "addmul!", r_gmpz_addmul_self, 2);
413
+ rb_define_method(cGMP_Z, "neg", r_gmpz_neg, 0);
414
+ rb_define_method(cGMP_Z, "neg!", r_gmpz_neg_self, 0);
415
+ rb_define_method(cGMP_Z, "-@", r_gmpz_neg, 0);
416
+ rb_define_method(cGMP_Z, "abs", r_gmpz_abs, 0);
417
+ rb_define_method(cGMP_Z, "abs!", r_gmpz_abs_self, 0);
418
+
419
+ // Integer Roots
420
+ rb_define_method(cGMP_Z, "root", r_gmpz_root, 1);
421
+ rb_define_method(cGMP_Z, "sqrt", r_gmpz_sqrt, 0);
422
+ rb_define_method(cGMP_Z, "sqrt!", r_gmpz_sqrt_self, 0);
423
+ rb_define_method(cGMP_Z, "sqrtrem", r_gmpz_sqrtrem, 0);
424
+ }