ghost_dm-core 1.3.0.beta

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.
Files changed (254) hide show
  1. data/.autotest +29 -0
  2. data/.document +5 -0
  3. data/.gitignore +35 -0
  4. data/.yardopts +1 -0
  5. data/Gemfile +65 -0
  6. data/LICENSE +20 -0
  7. data/README.md +269 -0
  8. data/Rakefile +4 -0
  9. data/dm-core.gemspec +24 -0
  10. data/lib/dm-core.rb +292 -0
  11. data/lib/dm-core/adapters.rb +222 -0
  12. data/lib/dm-core/adapters/abstract_adapter.rb +237 -0
  13. data/lib/dm-core/adapters/in_memory_adapter.rb +113 -0
  14. data/lib/dm-core/associations/many_to_many.rb +499 -0
  15. data/lib/dm-core/associations/many_to_one.rb +290 -0
  16. data/lib/dm-core/associations/one_to_many.rb +348 -0
  17. data/lib/dm-core/associations/one_to_one.rb +86 -0
  18. data/lib/dm-core/associations/relationship.rb +663 -0
  19. data/lib/dm-core/backwards.rb +13 -0
  20. data/lib/dm-core/collection.rb +1515 -0
  21. data/lib/dm-core/core_ext/kernel.rb +23 -0
  22. data/lib/dm-core/core_ext/pathname.rb +6 -0
  23. data/lib/dm-core/core_ext/symbol.rb +10 -0
  24. data/lib/dm-core/identity_map.rb +7 -0
  25. data/lib/dm-core/model.rb +874 -0
  26. data/lib/dm-core/model/hook.rb +103 -0
  27. data/lib/dm-core/model/is.rb +32 -0
  28. data/lib/dm-core/model/property.rb +249 -0
  29. data/lib/dm-core/model/relationship.rb +378 -0
  30. data/lib/dm-core/model/scope.rb +89 -0
  31. data/lib/dm-core/property.rb +866 -0
  32. data/lib/dm-core/property/binary.rb +21 -0
  33. data/lib/dm-core/property/boolean.rb +20 -0
  34. data/lib/dm-core/property/class.rb +17 -0
  35. data/lib/dm-core/property/date.rb +10 -0
  36. data/lib/dm-core/property/date_time.rb +10 -0
  37. data/lib/dm-core/property/decimal.rb +36 -0
  38. data/lib/dm-core/property/discriminator.rb +44 -0
  39. data/lib/dm-core/property/float.rb +16 -0
  40. data/lib/dm-core/property/integer.rb +22 -0
  41. data/lib/dm-core/property/invalid_value_error.rb +22 -0
  42. data/lib/dm-core/property/lookup.rb +27 -0
  43. data/lib/dm-core/property/numeric.rb +38 -0
  44. data/lib/dm-core/property/object.rb +34 -0
  45. data/lib/dm-core/property/serial.rb +14 -0
  46. data/lib/dm-core/property/string.rb +38 -0
  47. data/lib/dm-core/property/text.rb +9 -0
  48. data/lib/dm-core/property/time.rb +10 -0
  49. data/lib/dm-core/property_set.rb +177 -0
  50. data/lib/dm-core/query.rb +1366 -0
  51. data/lib/dm-core/query/conditions/comparison.rb +911 -0
  52. data/lib/dm-core/query/conditions/operation.rb +721 -0
  53. data/lib/dm-core/query/direction.rb +36 -0
  54. data/lib/dm-core/query/operator.rb +35 -0
  55. data/lib/dm-core/query/path.rb +114 -0
  56. data/lib/dm-core/query/sort.rb +39 -0
  57. data/lib/dm-core/relationship_set.rb +72 -0
  58. data/lib/dm-core/repository.rb +226 -0
  59. data/lib/dm-core/resource.rb +1214 -0
  60. data/lib/dm-core/resource/persistence_state.rb +75 -0
  61. data/lib/dm-core/resource/persistence_state/clean.rb +40 -0
  62. data/lib/dm-core/resource/persistence_state/deleted.rb +30 -0
  63. data/lib/dm-core/resource/persistence_state/dirty.rb +96 -0
  64. data/lib/dm-core/resource/persistence_state/immutable.rb +34 -0
  65. data/lib/dm-core/resource/persistence_state/persisted.rb +29 -0
  66. data/lib/dm-core/resource/persistence_state/transient.rb +80 -0
  67. data/lib/dm-core/spec/lib/adapter_helpers.rb +64 -0
  68. data/lib/dm-core/spec/lib/collection_helpers.rb +21 -0
  69. data/lib/dm-core/spec/lib/counter_adapter.rb +38 -0
  70. data/lib/dm-core/spec/lib/pending_helpers.rb +50 -0
  71. data/lib/dm-core/spec/lib/spec_helper.rb +74 -0
  72. data/lib/dm-core/spec/setup.rb +174 -0
  73. data/lib/dm-core/spec/shared/adapter_spec.rb +341 -0
  74. data/lib/dm-core/spec/shared/public/property_spec.rb +229 -0
  75. data/lib/dm-core/spec/shared/resource_spec.rb +1232 -0
  76. data/lib/dm-core/spec/shared/sel_spec.rb +111 -0
  77. data/lib/dm-core/spec/shared/semipublic/property_spec.rb +176 -0
  78. data/lib/dm-core/spec/shared/semipublic/query/conditions/abstract_comparison_spec.rb +261 -0
  79. data/lib/dm-core/support/assertions.rb +8 -0
  80. data/lib/dm-core/support/chainable.rb +18 -0
  81. data/lib/dm-core/support/deprecate.rb +12 -0
  82. data/lib/dm-core/support/descendant_set.rb +89 -0
  83. data/lib/dm-core/support/equalizer.rb +48 -0
  84. data/lib/dm-core/support/ext/array.rb +22 -0
  85. data/lib/dm-core/support/ext/blank.rb +25 -0
  86. data/lib/dm-core/support/ext/hash.rb +67 -0
  87. data/lib/dm-core/support/ext/module.rb +47 -0
  88. data/lib/dm-core/support/ext/object.rb +57 -0
  89. data/lib/dm-core/support/ext/string.rb +24 -0
  90. data/lib/dm-core/support/ext/try_dup.rb +12 -0
  91. data/lib/dm-core/support/hook.rb +405 -0
  92. data/lib/dm-core/support/inflections.rb +60 -0
  93. data/lib/dm-core/support/inflector/inflections.rb +211 -0
  94. data/lib/dm-core/support/inflector/methods.rb +151 -0
  95. data/lib/dm-core/support/lazy_array.rb +451 -0
  96. data/lib/dm-core/support/local_object_space.rb +13 -0
  97. data/lib/dm-core/support/logger.rb +201 -0
  98. data/lib/dm-core/support/mash.rb +176 -0
  99. data/lib/dm-core/support/naming_conventions.rb +90 -0
  100. data/lib/dm-core/support/ordered_set.rb +380 -0
  101. data/lib/dm-core/support/subject.rb +33 -0
  102. data/lib/dm-core/support/subject_set.rb +250 -0
  103. data/lib/dm-core/version.rb +3 -0
  104. data/script/performance.rb +275 -0
  105. data/script/profile.rb +218 -0
  106. data/spec/lib/rspec_immediate_feedback_formatter.rb +54 -0
  107. data/spec/public/associations/many_to_many/read_multiple_join_spec.rb +68 -0
  108. data/spec/public/associations/many_to_many_spec.rb +197 -0
  109. data/spec/public/associations/many_to_one_spec.rb +83 -0
  110. data/spec/public/associations/many_to_one_with_boolean_cpk_spec.rb +40 -0
  111. data/spec/public/associations/many_to_one_with_custom_fk_spec.rb +49 -0
  112. data/spec/public/associations/one_to_many_spec.rb +81 -0
  113. data/spec/public/associations/one_to_one_spec.rb +176 -0
  114. data/spec/public/associations/one_to_one_with_boolean_cpk_spec.rb +46 -0
  115. data/spec/public/collection_spec.rb +69 -0
  116. data/spec/public/finalize_spec.rb +76 -0
  117. data/spec/public/model/hook_spec.rb +246 -0
  118. data/spec/public/model/property_spec.rb +88 -0
  119. data/spec/public/model/relationship_spec.rb +1040 -0
  120. data/spec/public/model_spec.rb +462 -0
  121. data/spec/public/property/binary_spec.rb +41 -0
  122. data/spec/public/property/boolean_spec.rb +22 -0
  123. data/spec/public/property/class_spec.rb +28 -0
  124. data/spec/public/property/date_spec.rb +22 -0
  125. data/spec/public/property/date_time_spec.rb +22 -0
  126. data/spec/public/property/decimal_spec.rb +23 -0
  127. data/spec/public/property/discriminator_spec.rb +135 -0
  128. data/spec/public/property/float_spec.rb +22 -0
  129. data/spec/public/property/integer_spec.rb +22 -0
  130. data/spec/public/property/object_spec.rb +107 -0
  131. data/spec/public/property/serial_spec.rb +22 -0
  132. data/spec/public/property/string_spec.rb +22 -0
  133. data/spec/public/property/text_spec.rb +63 -0
  134. data/spec/public/property/time_spec.rb +22 -0
  135. data/spec/public/property_spec.rb +341 -0
  136. data/spec/public/resource_spec.rb +288 -0
  137. data/spec/public/sel_spec.rb +53 -0
  138. data/spec/public/setup_spec.rb +145 -0
  139. data/spec/public/shared/association_collection_shared_spec.rb +309 -0
  140. data/spec/public/shared/collection_finder_shared_spec.rb +267 -0
  141. data/spec/public/shared/collection_shared_spec.rb +1667 -0
  142. data/spec/public/shared/finder_shared_spec.rb +1629 -0
  143. data/spec/rcov.opts +6 -0
  144. data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
  145. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +13 -0
  146. data/spec/semipublic/associations/many_to_many_spec.rb +94 -0
  147. data/spec/semipublic/associations/many_to_one_spec.rb +63 -0
  148. data/spec/semipublic/associations/one_to_many_spec.rb +55 -0
  149. data/spec/semipublic/associations/one_to_one_spec.rb +53 -0
  150. data/spec/semipublic/associations/relationship_spec.rb +200 -0
  151. data/spec/semipublic/associations_spec.rb +177 -0
  152. data/spec/semipublic/collection_spec.rb +110 -0
  153. data/spec/semipublic/model_spec.rb +96 -0
  154. data/spec/semipublic/property/binary_spec.rb +13 -0
  155. data/spec/semipublic/property/boolean_spec.rb +47 -0
  156. data/spec/semipublic/property/class_spec.rb +33 -0
  157. data/spec/semipublic/property/date_spec.rb +43 -0
  158. data/spec/semipublic/property/date_time_spec.rb +46 -0
  159. data/spec/semipublic/property/decimal_spec.rb +83 -0
  160. data/spec/semipublic/property/discriminator_spec.rb +19 -0
  161. data/spec/semipublic/property/float_spec.rb +82 -0
  162. data/spec/semipublic/property/integer_spec.rb +82 -0
  163. data/spec/semipublic/property/lookup_spec.rb +29 -0
  164. data/spec/semipublic/property/serial_spec.rb +13 -0
  165. data/spec/semipublic/property/string_spec.rb +13 -0
  166. data/spec/semipublic/property/text_spec.rb +31 -0
  167. data/spec/semipublic/property/time_spec.rb +50 -0
  168. data/spec/semipublic/property_spec.rb +114 -0
  169. data/spec/semipublic/query/conditions/comparison_spec.rb +1501 -0
  170. data/spec/semipublic/query/conditions/operation_spec.rb +1294 -0
  171. data/spec/semipublic/query/path_spec.rb +471 -0
  172. data/spec/semipublic/query_spec.rb +3682 -0
  173. data/spec/semipublic/resource/state/clean_spec.rb +88 -0
  174. data/spec/semipublic/resource/state/deleted_spec.rb +78 -0
  175. data/spec/semipublic/resource/state/dirty_spec.rb +162 -0
  176. data/spec/semipublic/resource/state/immutable_spec.rb +105 -0
  177. data/spec/semipublic/resource/state/transient_spec.rb +162 -0
  178. data/spec/semipublic/resource/state_spec.rb +230 -0
  179. data/spec/semipublic/resource_spec.rb +23 -0
  180. data/spec/semipublic/shared/condition_shared_spec.rb +9 -0
  181. data/spec/semipublic/shared/resource_shared_spec.rb +199 -0
  182. data/spec/semipublic/shared/resource_state_shared_spec.rb +79 -0
  183. data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
  184. data/spec/spec.opts +5 -0
  185. data/spec/spec_helper.rb +38 -0
  186. data/spec/support/core_ext/hash.rb +10 -0
  187. data/spec/support/core_ext/inheritable_attributes.rb +46 -0
  188. data/spec/support/properties/huge_integer.rb +17 -0
  189. data/spec/unit/array_spec.rb +23 -0
  190. data/spec/unit/blank_spec.rb +73 -0
  191. data/spec/unit/data_mapper/ordered_set/append_spec.rb +26 -0
  192. data/spec/unit/data_mapper/ordered_set/clear_spec.rb +24 -0
  193. data/spec/unit/data_mapper/ordered_set/delete_spec.rb +28 -0
  194. data/spec/unit/data_mapper/ordered_set/each_spec.rb +19 -0
  195. data/spec/unit/data_mapper/ordered_set/empty_spec.rb +20 -0
  196. data/spec/unit/data_mapper/ordered_set/entries_spec.rb +22 -0
  197. data/spec/unit/data_mapper/ordered_set/eql_spec.rb +51 -0
  198. data/spec/unit/data_mapper/ordered_set/equal_value_spec.rb +84 -0
  199. data/spec/unit/data_mapper/ordered_set/hash_spec.rb +12 -0
  200. data/spec/unit/data_mapper/ordered_set/include_spec.rb +23 -0
  201. data/spec/unit/data_mapper/ordered_set/index_spec.rb +28 -0
  202. data/spec/unit/data_mapper/ordered_set/initialize_spec.rb +32 -0
  203. data/spec/unit/data_mapper/ordered_set/merge_spec.rb +36 -0
  204. data/spec/unit/data_mapper/ordered_set/shared/append_spec.rb +24 -0
  205. data/spec/unit/data_mapper/ordered_set/shared/clear_spec.rb +9 -0
  206. data/spec/unit/data_mapper/ordered_set/shared/delete_spec.rb +25 -0
  207. data/spec/unit/data_mapper/ordered_set/shared/each_spec.rb +17 -0
  208. data/spec/unit/data_mapper/ordered_set/shared/empty_spec.rb +9 -0
  209. data/spec/unit/data_mapper/ordered_set/shared/entries_spec.rb +9 -0
  210. data/spec/unit/data_mapper/ordered_set/shared/include_spec.rb +9 -0
  211. data/spec/unit/data_mapper/ordered_set/shared/index_spec.rb +13 -0
  212. data/spec/unit/data_mapper/ordered_set/shared/initialize_spec.rb +28 -0
  213. data/spec/unit/data_mapper/ordered_set/shared/merge_spec.rb +28 -0
  214. data/spec/unit/data_mapper/ordered_set/shared/size_spec.rb +13 -0
  215. data/spec/unit/data_mapper/ordered_set/shared/to_ary_spec.rb +11 -0
  216. data/spec/unit/data_mapper/ordered_set/size_spec.rb +27 -0
  217. data/spec/unit/data_mapper/ordered_set/to_ary_spec.rb +23 -0
  218. data/spec/unit/data_mapper/subject_set/append_spec.rb +47 -0
  219. data/spec/unit/data_mapper/subject_set/clear_spec.rb +34 -0
  220. data/spec/unit/data_mapper/subject_set/delete_spec.rb +40 -0
  221. data/spec/unit/data_mapper/subject_set/each_spec.rb +30 -0
  222. data/spec/unit/data_mapper/subject_set/empty_spec.rb +31 -0
  223. data/spec/unit/data_mapper/subject_set/entries_spec.rb +31 -0
  224. data/spec/unit/data_mapper/subject_set/get_spec.rb +34 -0
  225. data/spec/unit/data_mapper/subject_set/include_spec.rb +32 -0
  226. data/spec/unit/data_mapper/subject_set/named_spec.rb +33 -0
  227. data/spec/unit/data_mapper/subject_set/shared/append_spec.rb +18 -0
  228. data/spec/unit/data_mapper/subject_set/shared/clear_spec.rb +9 -0
  229. data/spec/unit/data_mapper/subject_set/shared/delete_spec.rb +9 -0
  230. data/spec/unit/data_mapper/subject_set/shared/each_spec.rb +9 -0
  231. data/spec/unit/data_mapper/subject_set/shared/empty_spec.rb +9 -0
  232. data/spec/unit/data_mapper/subject_set/shared/entries_spec.rb +9 -0
  233. data/spec/unit/data_mapper/subject_set/shared/get_spec.rb +9 -0
  234. data/spec/unit/data_mapper/subject_set/shared/include_spec.rb +9 -0
  235. data/spec/unit/data_mapper/subject_set/shared/named_spec.rb +9 -0
  236. data/spec/unit/data_mapper/subject_set/shared/size_spec.rb +13 -0
  237. data/spec/unit/data_mapper/subject_set/shared/to_ary_spec.rb +9 -0
  238. data/spec/unit/data_mapper/subject_set/shared/values_at_spec.rb +44 -0
  239. data/spec/unit/data_mapper/subject_set/size_spec.rb +42 -0
  240. data/spec/unit/data_mapper/subject_set/to_ary_spec.rb +34 -0
  241. data/spec/unit/data_mapper/subject_set/values_at_spec.rb +57 -0
  242. data/spec/unit/hash_spec.rb +28 -0
  243. data/spec/unit/hook_spec.rb +1235 -0
  244. data/spec/unit/inflections_spec.rb +16 -0
  245. data/spec/unit/lazy_array_spec.rb +1949 -0
  246. data/spec/unit/mash_spec.rb +312 -0
  247. data/spec/unit/module_spec.rb +71 -0
  248. data/spec/unit/object_spec.rb +38 -0
  249. data/spec/unit/try_dup_spec.rb +46 -0
  250. data/tasks/ci.rake +1 -0
  251. data/tasks/spec.rake +38 -0
  252. data/tasks/yard.rake +9 -0
  253. data/tasks/yardstick.rake +19 -0
  254. metadata +365 -0
@@ -0,0 +1,3 @@
1
+ module DataMapper
2
+ VERSION = '1.3.0.beta'
3
+ end
@@ -0,0 +1,275 @@
1
+ #!/usr/bin/env ruby -Ku
2
+
3
+ require 'ftools'
4
+ require 'rubygems'
5
+
6
+ gem 'activerecord', '~> 2.3.4'
7
+ gem 'addressable', '~> 2.1'
8
+ gem 'faker', '~> 0.3.1'
9
+ gem 'rbench', '~> 0.2.3'
10
+
11
+ require 'active_record'
12
+ require 'addressable/uri'
13
+ require 'faker'
14
+ require 'rbench'
15
+
16
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'dm-core'))
17
+
18
+ socket_file = Pathname.glob(%w[
19
+ /opt/local/var/run/mysql5/mysqld.sock
20
+ tmp/mysqld.sock
21
+ /tmp/mysqld.sock
22
+ tmp/mysql.sock
23
+ /tmp/mysql.sock
24
+ /var/mysql/mysql.sock
25
+ /var/run/mysqld/mysqld.sock
26
+ ]).find { |path| path.socket? }
27
+
28
+ configuration_options = {
29
+ :adapter => 'mysql',
30
+ :username => 'root',
31
+ :password => '',
32
+ :database => 'dm_core_test',
33
+ }
34
+
35
+ configuration_options[:socket] = socket_file unless socket_file.nil?
36
+
37
+ log_dir = DataMapper.root / 'log'
38
+ log_dir.mkdir unless log_dir.directory?
39
+
40
+ DataMapper::Logger.new(log_dir / 'dm.log', :off)
41
+ adapter = DataMapper.setup(:default, "mysql://root@localhost/dm_core_test?socket=#{socket_file}")
42
+
43
+ if configuration_options[:adapter]
44
+ sqlfile = File.join(File.dirname(__FILE__), '..', 'tmp', 'performance.sql')
45
+ mysql_bin = %w[ mysql mysql5 ].select { |bin| `which #{bin}`.length > 0 }
46
+ mysqldump_bin = %w[ mysqldump mysqldump5 ].select { |bin| `which #{bin}`.length > 0 }
47
+ end
48
+
49
+ ActiveRecord::Base.logger = Logger.new(log_dir / 'ar.log')
50
+ ActiveRecord::Base.logger.level = 0
51
+
52
+ ActiveRecord::Base.establish_connection(configuration_options)
53
+
54
+ class ARExhibit < ActiveRecord::Base #:nodoc:
55
+ set_table_name 'exhibits'
56
+
57
+ belongs_to :user, :class_name => 'ARUser', :foreign_key => 'user_id'
58
+ end
59
+
60
+ class ARUser < ActiveRecord::Base #:nodoc:
61
+ set_table_name 'users'
62
+
63
+ has_many :exhibits, :foreign_key => 'user_id'
64
+ end
65
+
66
+ ARExhibit.find_by_sql('SELECT 1')
67
+
68
+ class User
69
+ include DataMapper::Resource
70
+
71
+ property :id, Serial
72
+ property :name, String
73
+ property :email, String
74
+ property :about, Text, :lazy => false
75
+ property :created_on, Date
76
+ end
77
+
78
+ class Exhibit
79
+ include DataMapper::Resource
80
+
81
+ property :id, Serial
82
+ property :name, String
83
+ property :zoo_id, Integer
84
+ property :user_id, Integer
85
+ property :notes, Text, :lazy => false
86
+ property :created_on, Date
87
+
88
+ belongs_to :user
89
+ end
90
+
91
+ DataMapper.auto_migrate!
92
+
93
+ def touch_attributes(*exhibits)
94
+ exhibits.flatten.each do |exhibit|
95
+ exhibit.id
96
+ exhibit.name
97
+ exhibit.created_on
98
+ end
99
+ end
100
+
101
+ def touch_relationships(*exhibits)
102
+ exhibits.flatten.each do |exhibit|
103
+ exhibit.id
104
+ exhibit.name
105
+ exhibit.created_on
106
+ exhibit.user
107
+ end
108
+ end
109
+
110
+ c = configuration_options
111
+
112
+ if sqlfile && File.exists?(sqlfile)
113
+ puts "Found data-file. Importing from #{sqlfile}"
114
+ #adapter.execute("LOAD DATA LOCAL INFILE '#{sqlfile}' INTO TABLE exhibits")
115
+ `#{mysql_bin} -u #{c[:username]} #{"-p#{c[:password]}" unless c[:password].blank?} #{c[:database]} < #{sqlfile}`
116
+ else
117
+ puts 'Generating data for benchmarking...'
118
+
119
+ # pre-compute the insert statements and fake data compilation,
120
+ # so the benchmarks below show the actual runtime for the execute
121
+ # method, minus the setup steps
122
+
123
+ # Using the same paragraph for all exhibits because it is very slow
124
+ # to generate unique paragraphs for all exhibits.
125
+ notes = Faker::Lorem.paragraphs.join($/)
126
+ today = Date.today
127
+
128
+ puts 'Inserting 10,000 users and exhibits...'
129
+ 10_000.times do
130
+ user = User.create(
131
+ :created_on => today,
132
+ :name => Faker::Name.name,
133
+ :email => Faker::Internet.email
134
+ )
135
+
136
+ Exhibit.create(
137
+ :created_on => today,
138
+ :name => Faker::Company.name,
139
+ :user => user,
140
+ :notes => notes,
141
+ :zoo_id => rand(10).ceil
142
+ )
143
+ end
144
+
145
+ if sqlfile
146
+ answer = nil
147
+ until answer && answer[/\A(?:y(?:es)?|no?)\b/i]
148
+ print('Would you like to dump data into tmp/performance.sql (for faster setup)? [Yn]');
149
+ STDOUT.flush
150
+ answer = gets
151
+ end
152
+
153
+ if %w[ y yes ].include?(answer.downcase)
154
+ File.makedirs(File.dirname(sqlfile))
155
+ #adapter.execute("SELECT * INTO OUTFILE '#{sqlfile}' FROM exhibits;")
156
+ `#{mysqldump_bin} -u #{c[:username]} #{"-p#{c[:password]}" unless c[:password].blank?} #{c[:database]} exhibits users > #{sqlfile}`
157
+ puts "File saved\n"
158
+ end
159
+ end
160
+ end
161
+
162
+ TIMES = ENV.key?('x') ? ENV['x'].to_i : 10_000
163
+
164
+ puts 'You can specify how many times you want to run the benchmarks with rake:perf x=(number)'
165
+ puts 'Some tasks will be run 10 and 1000 times less than (number)'
166
+ puts "Benchmarks will now run #{TIMES} times"
167
+ # Inform about slow benchmark
168
+ # answer = nil
169
+ # until answer && answer[/^$|y|yes|n|no/]
170
+ # print("A slow benchmark exposing problems with SEL is newly added. It takes approx. 20s\n");
171
+ # print("you have scheduled it to run #{TIMES / 100} times.\nWould you still include the particular benchmark? [Yn]")
172
+ # STDOUT.flush
173
+ # answer = gets
174
+ # end
175
+ # run_rel_bench = answer[/^$|y|yes/] ? true : false
176
+
177
+
178
+ RBench.run(TIMES) do
179
+
180
+ column :times
181
+ column :ar, :title => 'AR 2.3.2'
182
+ column :dm, :title => "DM #{DataMapper::VERSION}"
183
+ column :diff, :compare => [:ar, :dm]
184
+
185
+ report 'Model#id', (TIMES * 100).ceil do
186
+ ar_obj = ARExhibit.find(1)
187
+ dm_obj = Exhibit.get(1)
188
+
189
+ ar { ar_obj.id }
190
+ dm { dm_obj.id }
191
+ end
192
+
193
+ report 'Model.new (instantiation)' do
194
+ ar { ARExhibit.new }
195
+ dm { Exhibit.new }
196
+ end
197
+
198
+ report 'Model.new (setting attributes)' do
199
+ attrs = { :name => 'sam', :zoo_id => 1 }
200
+ ar { ARExhibit.new(attrs) }
201
+ dm { Exhibit.new(attrs) }
202
+ end
203
+
204
+ report 'Model.get specific (not cached)' do
205
+ ActiveRecord::Base.uncached { ar { touch_attributes(ARExhibit.find(1)) } }
206
+ dm { touch_attributes(Exhibit.get(1)) }
207
+ end
208
+
209
+ report 'Model.get specific (cached)' do
210
+ ActiveRecord::Base.cache { ar { touch_attributes(ARExhibit.find(1)) } }
211
+ Exhibit.repository(:default) { dm { touch_attributes(Exhibit.get(1)) } }
212
+ end
213
+
214
+ report 'Model.first' do
215
+ ar { touch_attributes(ARExhibit.first) }
216
+ dm { touch_attributes(Exhibit.first) }
217
+ end
218
+
219
+ report 'Model.all limit(100)', (TIMES / 10).ceil do
220
+ ar { touch_attributes(ARExhibit.find(:all, :limit => 100)) }
221
+ dm { touch_attributes(Exhibit.all(:limit => 100)) }
222
+ end
223
+
224
+ report 'Model.all limit(100) with relationship', (TIMES / 10).ceil do
225
+ ar { touch_relationships(ARExhibit.all(:limit => 100, :include => [ :user ])) }
226
+ dm { touch_relationships(Exhibit.all(:limit => 100)) }
227
+ end
228
+
229
+ report 'Model.all limit(10,000)', (TIMES / 1000).ceil do
230
+ ar { touch_attributes(ARExhibit.find(:all, :limit => 10_000)) }
231
+ dm { touch_attributes(Exhibit.all(:limit => 10_000)) }
232
+ end
233
+
234
+ exhibit = {
235
+ :name => Faker::Company.name,
236
+ :zoo_id => rand(10).ceil,
237
+ :notes => Faker::Lorem.paragraphs.join($/),
238
+ :created_on => Date.today
239
+ }
240
+
241
+ report 'Model.create' do
242
+ ar { ARExhibit.create(exhibit) }
243
+ dm { Exhibit.create(exhibit) }
244
+ end
245
+
246
+ report 'Resource#attributes=' do
247
+ attrs_first = { :name => 'sam', :zoo_id => 1 }
248
+ attrs_second = { :name => 'tom', :zoo_id => 1 }
249
+ ar { exhibit = ARExhibit.new(attrs_first); exhibit.attributes = attrs_second }
250
+ dm { exhibit = Exhibit.new(attrs_first); exhibit.attributes = attrs_second }
251
+ end
252
+
253
+ report 'Resource#update' do
254
+ ar { ARExhibit.find(1).update_attributes(:name => 'bob') }
255
+ dm { Exhibit.get(1).update(:name => 'bob') }
256
+ end
257
+
258
+ report 'Resource#destroy' do
259
+ ar { ARExhibit.first.destroy }
260
+ dm { Exhibit.first.destroy }
261
+ end
262
+
263
+ report 'Model.transaction' do
264
+ ar { ARExhibit.transaction { ARExhibit.new } }
265
+ dm { Exhibit.transaction { Exhibit.new } }
266
+ end
267
+
268
+ summary 'Total'
269
+ end
270
+
271
+ connection = adapter.send(:open_connection)
272
+ command = connection.create_command('DROP TABLE exhibits')
273
+ command = connection.create_command('DROP TABLE users')
274
+ command.execute_non_query rescue nil
275
+ connection.close
data/script/profile.rb ADDED
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env ruby -Ku
2
+
3
+ require 'ftools'
4
+ require 'rubygems'
5
+
6
+ gem 'addressable', '~> 2.1'
7
+ gem 'faker', '~> 0.3.1'
8
+ gem 'ruby-prof', '~> 0.7.3'
9
+
10
+ require 'addressable/uri'
11
+ require 'faker'
12
+ require 'ruby-prof'
13
+
14
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'dm-core'))
15
+
16
+ TEXT_OUTPUT = DataMapper.root / 'profile_results.txt'
17
+ HTML_OUTPUT = DataMapper.root / 'profile_results.html'
18
+ CALL_OUTPUT = DataMapper.root / 'profile_results.prof'
19
+
20
+ SOCKET_FILE = Pathname.glob(%w[
21
+ /opt/local/var/run/mysql5/mysqld.sock
22
+ /tmp/mysqld.sock
23
+ /tmp/mysql.sock
24
+ /var/mysql/mysql.sock
25
+ /var/run/mysqld/mysqld.sock
26
+ ]).find { |path| path.socket? }
27
+
28
+ configuration_options = {
29
+ :adapter => 'mysql',
30
+ :database => 'dm_core_test',
31
+ :host => 'localhost',
32
+ :username => 'root',
33
+ :password => '',
34
+ :socket => SOCKET_FILE,
35
+ }
36
+
37
+ DataMapper::Logger.new(DataMapper.root / 'log' / 'dm.log', :debug)
38
+ adapter = DataMapper.setup(:default, configuration_options)
39
+
40
+ if configuration_options[:adapter]
41
+ sqlfile = File.join(File.dirname(__FILE__), '..', 'tmp', 'performance.sql')
42
+ mysql_bin = %w[ mysql mysql5 ].select { |bin| `which #{bin}`.length > 0 }
43
+ mysqldump_bin = %w[ mysqldump mysqldump5 ].select { |bin| `which #{bin}`.length > 0 }
44
+ end
45
+
46
+ class User
47
+ include DataMapper::Resource
48
+
49
+ property :id, Serial
50
+ property :name, String
51
+ property :email, String
52
+ property :about, Text, :lazy => false
53
+ property :created_on, Date
54
+ end
55
+
56
+ class Exhibit
57
+ include DataMapper::Resource
58
+
59
+ property :id, Serial
60
+ property :name, String
61
+ property :zoo_id, Integer
62
+ property :user_id, Integer
63
+ property :notes, Text, :lazy => false
64
+ property :created_on, Date
65
+
66
+ belongs_to :user
67
+ end
68
+
69
+ DataMapper.auto_migrate!
70
+
71
+ def touch_attributes(*exhibits)
72
+ exhibits.flatten.each do |exhibit|
73
+ exhibit.id
74
+ exhibit.name
75
+ exhibit.created_on
76
+ end
77
+ end
78
+
79
+ def touch_relationships(*exhibits)
80
+ exhibits.flatten.each do |exhibit|
81
+ exhibit.id
82
+ exhibit.name
83
+ exhibit.created_on
84
+ exhibit.user
85
+ end
86
+ end
87
+
88
+ # RubyProf, making profiling Ruby pretty since 1899!
89
+ def profile(&b)
90
+ results = RubyProf.profile(&b)
91
+
92
+ TEXT_OUTPUT.open('w+') do |file|
93
+ RubyProf::FlatPrinter.new(results).print(file)
94
+ end
95
+
96
+ HTML_OUTPUT.open('w+') do |file|
97
+ RubyProf::GraphHtmlPrinter.new(results).print(file)
98
+ end
99
+
100
+ CALL_OUTPUT.open('w+') do |file|
101
+ RubyProf::CallTreePrinter.new(results).print(file)
102
+ end
103
+ end
104
+
105
+ c = configuration_options
106
+
107
+ if sqlfile && File.exists?(sqlfile)
108
+ puts "Found data-file. Importing from #{sqlfile}"
109
+ #adapter.execute("LOAD DATA LOCAL INFILE '#{sqlfile}' INTO TABLE exhibits")
110
+ `#{mysql_bin} -u #{c[:username]} #{"-p#{c[:password]}" unless c[:password].blank?} #{c[:database]} < #{sqlfile}`
111
+ else
112
+ puts 'Generating data for benchmarking...'
113
+
114
+ # pre-compute the insert statements and fake data compilation,
115
+ # so the benchmarks below show the actual runtime for the execute
116
+ # method, minus the setup steps
117
+
118
+ # Using the same paragraph for all exhibits because it is very slow
119
+ # to generate unique paragraphs for all exhibits.
120
+ notes = Faker::Lorem.paragraphs.join($/)
121
+ today = Date.today
122
+
123
+ puts 'Inserting 10,000 users and exhibits...'
124
+ 10_000.times do
125
+ user = User.create(
126
+ :created_on => today,
127
+ :name => Faker::Name.name,
128
+ :email => Faker::Internet.email
129
+ )
130
+
131
+ Exhibit.create(
132
+ :created_on => today,
133
+ :name => Faker::Company.name,
134
+ :user => user,
135
+ :notes => notes,
136
+ :zoo_id => rand(10).ceil
137
+ )
138
+ end
139
+
140
+ if sqlfile
141
+ answer = nil
142
+ until answer && answer[/\A(?:y(?:es)?|no?)\b/i]
143
+ print('Would you like to dump data into tmp/performance.sql (for faster setup)? [Yn]');
144
+ STDOUT.flush
145
+ answer = gets
146
+ end
147
+
148
+ if %w[ y yes ].include?(answer.downcase)
149
+ File.makedirs(File.dirname(sqlfile))
150
+ #adapter.execute("SELECT * INTO OUTFILE '#{sqlfile}' FROM exhibits;")
151
+ `#{mysqldump_bin} -u #{c[:username]} #{"-p#{c[:password]}" unless c[:password].blank?} #{c[:database]} exhibits users > #{sqlfile}`
152
+ puts "File saved\n"
153
+ end
154
+ end
155
+ end
156
+
157
+ TIMES = 10_000
158
+
159
+ exhibits = Exhibit.all.to_a
160
+
161
+ profile do
162
+ # dm_obj = Exhibit.get(1)
163
+ # puts 'Model#id'
164
+ # (TIMES * 100).times { dm_obj.id }
165
+ #
166
+ # puts 'Model.new (instantiation)'
167
+ # TIMES.times { Exhibit.new }
168
+ #
169
+ # puts 'Model.new (setting attributes)'
170
+ # TIMES.times { Exhibit.new(:name => 'sam', :zoo_id => 1) }
171
+ #
172
+ # puts 'Model.get specific (not cached)'
173
+ # TIMES.times { touch_attributes(Exhibit.get(1)) }
174
+ #
175
+ # puts 'Model.get specific (cached)'
176
+ # repository(:default) do
177
+ # TIMES.times { touch_attributes(Exhibit.get(1)) }
178
+ # end
179
+
180
+ puts 'Model.first'
181
+ TIMES.times { touch_attributes(Exhibit.first) }
182
+
183
+ # puts 'Model.all limit(100)'
184
+ # (TIMES / 10).ceil.times { touch_attributes(Exhibit.all(:limit => 100)) }
185
+ #
186
+ # puts 'Model.all limit(100) with relationship'
187
+ # (TIMES / 10).ceil.times { touch_relationships(Exhibit.all(:limit => 100)) }
188
+ #
189
+ # puts 'Model.all limit(10,000)'
190
+ # (TIMES / 1000).ceil { touch_attributes(Exhibit.all(:limit => 10_000)) }
191
+ #
192
+ # exhibit = {
193
+ # :name => Faker::Company.name,
194
+ # :zoo_id => rand(10).ceil,
195
+ # :notes => Faker::Lorem.paragraphs.join($/),
196
+ # :created_on => Date.today
197
+ # }
198
+ #
199
+ # puts 'Model.create'
200
+ # TIMES.times { Exhibit.create(exhibit) }
201
+ #
202
+ # attrs_first = { :name => 'sam', :zoo_id => 1 }
203
+ # attrs_second = { :name => 'tom', :zoo_id => 1 }
204
+ #
205
+ # puts 'Resource#attributes='
206
+ # TIMES.times { exhibit = Exhibit.new(attrs_first); exhibit.attributes = attrs_second }
207
+ #
208
+ # puts 'Resource#update'
209
+ # TIMES.times { |index| exhibit = exhibits[index]; exhibit.name = 'bob'; exhibit.save }
210
+ #
211
+ # puts 'Resource#destroy'
212
+ # TIMES.times { |index| exhibits[index].destroy }
213
+ #
214
+ # puts 'Model.transaction'
215
+ # TIMES.times { Exhibit.transaction { Exhibit.new } }
216
+ end
217
+
218
+ puts "Done!"