architect4r 0.3.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.
Files changed (110) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +4 -0
  3. data/Gemfile.lock +53 -0
  4. data/Guardfile +10 -0
  5. data/License +20 -0
  6. data/README.md +62 -0
  7. data/Rakefile +40 -0
  8. data/ReleaseNotes.md +33 -0
  9. data/Roadmap.md +31 -0
  10. data/Specs.md +21 -0
  11. data/architect4r.gemspec +31 -0
  12. data/lib/architect4r.rb +66 -0
  13. data/lib/architect4r/adapters/carrier_wave.rb +64 -0
  14. data/lib/architect4r/core/configuration.rb +148 -0
  15. data/lib/architect4r/core/cypher_methods.rb +47 -0
  16. data/lib/architect4r/core/management_methods.rb +129 -0
  17. data/lib/architect4r/core/node_methods.rb +73 -0
  18. data/lib/architect4r/core/relationship_methods.rb +82 -0
  19. data/lib/architect4r/generic_node.rb +7 -0
  20. data/lib/architect4r/has_node.rb +80 -0
  21. data/lib/architect4r/instance_manager.rb +47 -0
  22. data/lib/architect4r/model/callbacks.rb +19 -0
  23. data/lib/architect4r/model/connection.rb +29 -0
  24. data/lib/architect4r/model/links_query_interface.rb +23 -0
  25. data/lib/architect4r/model/node.rb +117 -0
  26. data/lib/architect4r/model/persistency.rb +95 -0
  27. data/lib/architect4r/model/properties.rb +166 -0
  28. data/lib/architect4r/model/queries.rb +38 -0
  29. data/lib/architect4r/model/relationship.rb +105 -0
  30. data/lib/architect4r/model/relationships.rb +16 -0
  31. data/lib/architect4r/model/validations.rb +11 -0
  32. data/lib/architect4r/server.rb +96 -0
  33. data/lib/architect4r/version.rb +3 -0
  34. data/spec/architect4r_spec.rb +9 -0
  35. data/spec/core/configuration_spec.rb +54 -0
  36. data/spec/core/cypher_methods_spec.rb +29 -0
  37. data/spec/core/node_methods_spec.rb +47 -0
  38. data/spec/core/relationship_methods_spec.rb +92 -0
  39. data/spec/fixtures/architect4r.yml +21 -0
  40. data/spec/fixtures/graph.db.default/active_tx_log +1 -0
  41. data/spec/fixtures/graph.db.default/index/lucene-store.db +0 -0
  42. data/spec/fixtures/graph.db.default/index/lucene.log.1 +0 -0
  43. data/spec/fixtures/graph.db.default/index/lucene.log.active +0 -0
  44. data/spec/fixtures/graph.db.default/index/lucene.log.v0 +0 -0
  45. data/spec/fixtures/graph.db.default/index/lucene.log.v1 +0 -0
  46. data/spec/fixtures/graph.db.default/index/lucene.log.v2 +0 -0
  47. data/spec/fixtures/graph.db.default/lock +0 -0
  48. data/spec/fixtures/graph.db.default/messages.log +183 -0
  49. data/spec/fixtures/graph.db.default/neostore +0 -0
  50. data/spec/fixtures/graph.db.default/neostore.id +0 -0
  51. data/spec/fixtures/graph.db.default/neostore.nodestore.db +0 -0
  52. data/spec/fixtures/graph.db.default/neostore.nodestore.db.id +0 -0
  53. data/spec/fixtures/graph.db.default/neostore.propertystore.db +0 -0
  54. data/spec/fixtures/graph.db.default/neostore.propertystore.db.arrays +0 -0
  55. data/spec/fixtures/graph.db.default/neostore.propertystore.db.arrays.id +0 -0
  56. data/spec/fixtures/graph.db.default/neostore.propertystore.db.id +0 -0
  57. data/spec/fixtures/graph.db.default/neostore.propertystore.db.index +0 -0
  58. data/spec/fixtures/graph.db.default/neostore.propertystore.db.index.id +0 -0
  59. data/spec/fixtures/graph.db.default/neostore.propertystore.db.index.keys +0 -0
  60. data/spec/fixtures/graph.db.default/neostore.propertystore.db.index.keys.id +0 -0
  61. data/spec/fixtures/graph.db.default/neostore.propertystore.db.strings +0 -0
  62. data/spec/fixtures/graph.db.default/neostore.propertystore.db.strings.id +0 -0
  63. data/spec/fixtures/graph.db.default/neostore.relationshipstore.db +0 -0
  64. data/spec/fixtures/graph.db.default/neostore.relationshipstore.db.id +0 -0
  65. data/spec/fixtures/graph.db.default/neostore.relationshiptypestore.db +0 -0
  66. data/spec/fixtures/graph.db.default/neostore.relationshiptypestore.db.id +0 -0
  67. data/spec/fixtures/graph.db.default/neostore.relationshiptypestore.db.names +0 -0
  68. data/spec/fixtures/graph.db.default/neostore.relationshiptypestore.db.names.id +0 -0
  69. data/spec/fixtures/graph.db.default/nioneo_logical.log.1 +0 -0
  70. data/spec/fixtures/graph.db.default/nioneo_logical.log.active +0 -0
  71. data/spec/fixtures/graph.db.default/tm_tx_log.1 +0 -0
  72. data/spec/fixtures/graph.db.default/upgrade_backup/active_tx_log +1 -0
  73. data/spec/fixtures/graph.db.default/upgrade_backup/messages.log +142 -0
  74. data/spec/fixtures/graph.db.default/upgrade_backup/neostore +0 -0
  75. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.id +0 -0
  76. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.nodestore.db +0 -0
  77. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.nodestore.db.id +0 -0
  78. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db +0 -0
  79. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.arrays +0 -0
  80. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.arrays.id +0 -0
  81. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.id +0 -0
  82. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.index +0 -0
  83. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.index.id +0 -0
  84. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.index.keys +0 -0
  85. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.index.keys.id +0 -0
  86. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.strings +0 -0
  87. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.strings.id +0 -0
  88. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshipstore.db +0 -0
  89. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshipstore.db.id +0 -0
  90. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshiptypestore.db +0 -0
  91. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshiptypestore.db.id +0 -0
  92. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshiptypestore.db.names +0 -0
  93. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshiptypestore.db.names.id +0 -0
  94. data/spec/fixtures/graph.db.default/upgrade_backup/nioneo_logical.log.active +0 -0
  95. data/spec/fixtures/graph.db.default/upgrade_backup/nioneo_logical.log.v0 +0 -0
  96. data/spec/fixtures/graph.db.default/upgrade_backup/nioneo_logical.log.v1 +0 -0
  97. data/spec/fixtures/graph.db.default/upgrade_backup/nioneo_logical.log.v2 +0 -0
  98. data/spec/fixtures/graph.db.default/upgrade_backup/tm_tx_log.1 +0 -0
  99. data/spec/has_node_spec.rb +87 -0
  100. data/spec/model/links_query_interface_spec.rb +22 -0
  101. data/spec/model/links_spec.rb +26 -0
  102. data/spec/model/node_spec.rb +48 -0
  103. data/spec/model/persistency_spec.rb +98 -0
  104. data/spec/model/properties_spec.rb +165 -0
  105. data/spec/model/queries_spec.rb +50 -0
  106. data/spec/model/relationship_spec.rb +63 -0
  107. data/spec/model/validations_spec.rb +31 -0
  108. data/spec/server_spec.rb +33 -0
  109. data/spec/spec_helper.rb +115 -0
  110. metadata +377 -0
@@ -0,0 +1,7 @@
1
+ module Architect4r
2
+
3
+ class GenericNode < Model::Node
4
+
5
+ end
6
+
7
+ end
@@ -0,0 +1,80 @@
1
+ module Architect4r
2
+
3
+ # has_node :node, AccountNode, :sync => [:firstname, :lastname]
4
+ module HasNode
5
+
6
+ # Easier integration pattern
7
+ extend ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+
11
+ def has_node(attr_name, model_name, options={})
12
+
13
+ #if self.respond_to?(:after_create)
14
+ after_create :"architect4r_create_#{attr_name}"
15
+ after_update :"architect4r_sync_#{attr_name}"
16
+ after_destroy :"architect4r_destroy_#{attr_name}"
17
+ #end
18
+
19
+ # Create a neo4j node
20
+ define_method("architect4r_create_#{attr_name}") do
21
+ return nil unless self.id
22
+
23
+ new_node = model_name.new
24
+ new_node.write_attribute(:architect4r_sync_id, self.id)
25
+
26
+ options[:sync].to_a.each do |prop|
27
+ new_node.send("#{prop}=", self.send(prop))
28
+ end
29
+
30
+ if new_node.save
31
+ new_node
32
+ else
33
+ nil
34
+ end
35
+ instance_variable_set("@#{attr_name}", new_node)
36
+ end
37
+
38
+ # Create a getter method
39
+ define_method(attr_name) do
40
+ # Only available if the database record is already created
41
+ return nil unless self.id
42
+
43
+ # Get or create the graph db node
44
+ the_node = instance_variable_get("@#{attr_name}")
45
+ the_node ||= begin
46
+ linked_node = model_name.find_by_cypher("start s=node(#{model_name.model_root.id}) match s<-[:model_type]-d where d.architect4r_sync_id = #{self.id} return d", "d").first
47
+ linked_node ||= self.send("architect4r_create_#{attr_name}")
48
+ instance_variable_set("@#{attr_name}", linked_node)
49
+ end
50
+ end
51
+
52
+ define_method("architect4r_destroy_#{attr_name}") do
53
+ self.send("#{attr_name}").destroy
54
+ end
55
+
56
+
57
+ # Keep the graph node in sync, so it reflects the name
58
+ #
59
+ define_method("architect4r_sync_#{attr_name}") do
60
+ changed = false
61
+
62
+ options[:sync].to_a.each do |prop|
63
+ if self.node.send("#{prop}") != self.send(prop)
64
+ self.node.send("#{prop}=", self.send(prop))
65
+ changed = true
66
+ end
67
+ end
68
+
69
+ if changed
70
+ self.node.save
71
+ end
72
+ end
73
+
74
+ end
75
+
76
+ end
77
+
78
+ end
79
+
80
+ end
@@ -0,0 +1,47 @@
1
+ module Architect4r
2
+ class InstanceManager
3
+
4
+ def initialize(path)
5
+ @path = path
6
+ end
7
+
8
+ def server_path
9
+ @path
10
+ end
11
+
12
+ def start
13
+ %x[#{server_path}/bin/neo4j start]
14
+ end
15
+
16
+ def stop
17
+ %x[#{server_path}/bin/neo4j stop]
18
+ end
19
+
20
+ def restart
21
+ %x[#{server_path}/bin/neo4j restart]
22
+ end
23
+
24
+ def reset
25
+ self.stop
26
+
27
+ # Reset the database
28
+ FileUtils.rm_rf("#{server_path}/data/graph.db")
29
+ FileUtils.mkdir("#{server_path}/data/graph.db")
30
+
31
+ # Remove log files
32
+ FileUtils.rm_rf("#{server_path}/data/log")
33
+ FileUtils.mkdir("#{server_path}/data/log")
34
+
35
+ # Start the server
36
+ self.start
37
+ end
38
+
39
+ def reset_to_sample_data(from)
40
+ self.stop
41
+ FileUtils.rm_rf("#{server_path}/data/graph.db")
42
+ FileUtils.cp_r(from, "#{server_path}/data/graph.db/")
43
+ self.start
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ module Architect4r
4
+ module Model
5
+
6
+ module Callbacks
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ extend ActiveModel::Callbacks
11
+ include ActiveModel::Validations::Callbacks
12
+
13
+ define_model_callbacks :initialize, :only => :after
14
+ define_model_callbacks :create, :destroy, :save, :update
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ module Architect4r
2
+ module Model
3
+ module Connection
4
+ extend ActiveSupport::Concern
5
+
6
+ module InstanceMethods
7
+
8
+ def connection
9
+ self.class.connection
10
+ end
11
+
12
+ end
13
+
14
+ module ClassMethods
15
+
16
+ def use_server(server)
17
+ @connection = server
18
+ end
19
+
20
+ def connection
21
+ # TODO: apply configuration
22
+ @connection || Server.new
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,23 @@
1
+ module Architect4r
2
+ module Model
3
+ class LinksQueryInterface
4
+
5
+ def initialize(owner)
6
+ @owner = owner
7
+ end
8
+
9
+ def incoming
10
+
11
+ end
12
+
13
+ def outgoing
14
+
15
+ end
16
+
17
+ def both
18
+
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,117 @@
1
+ module Architect4r
2
+
3
+ module Model
4
+
5
+ class Node
6
+
7
+ #
8
+ # architect4r extensions
9
+ #
10
+ include Architect4r::Model::Connection
11
+ include Architect4r::Model::Callbacks
12
+ include Architect4r::Model::Persistency
13
+ include Architect4r::Model::Queries
14
+ include Architect4r::Model::Relationships
15
+
16
+ def self.inherited(subklass)
17
+ super
18
+ subklass.send(:include, ActiveModel::Conversion)
19
+ subklass.extend ActiveModel::Naming
20
+ subklass.send(:include, Architect4r::Model::Properties)
21
+ subklass.send(:include, Architect4r::Model::Validations)
22
+
23
+ subklass.class_exec do
24
+
25
+ def self.model_root
26
+ @model_root ||= begin
27
+ # Check if there is already a model root,
28
+ query = "start root = node(0) match (root)-[r:#{ model_root_relation_type}]->(x) where r.architect4r_type and r.architect4r_type = '#{name}' return x"
29
+ the_root = connection.execute_cypher(query).to_a.first
30
+ the_root &&= the_root['x']
31
+
32
+ # otherwise create one
33
+ the_root ||= begin
34
+ m_root = connection.create_node(:name => "#{name} Root")
35
+ connection.create_relationship(0, m_root, model_root_relation_type, { 'architect4r_type' => name })
36
+ m_root
37
+ end
38
+
39
+ # Return model root node
40
+ GenericNode.send(:build_from_database, the_root)
41
+ end
42
+ end
43
+
44
+ end
45
+ end
46
+
47
+ attr_accessor :raw_data
48
+
49
+ def initialize(properties={})
50
+ run_callbacks :initialize do
51
+ parse_properties(properties)
52
+ end
53
+ end
54
+
55
+ # Create the document. Validation is enabled by default and will return
56
+ # false if the document is not valid. If all goes well, the document will
57
+ # be returned.
58
+ def create(options = {})
59
+ run_callbacks :create do
60
+ run_callbacks :save do
61
+ # only create valid records
62
+ return false unless perform_validations(options)
63
+
64
+ # perform creation
65
+ if result = connection.create_node(self._to_database_hash)
66
+ self.raw_data = result
67
+
68
+ # Link the node with a model root node
69
+ connection.create_relationship(self.id, self.class.model_root.id, 'model_type')
70
+ end
71
+
72
+ # if something goes wrong we receive a nil value and return false
73
+ !result.nil?
74
+ end
75
+ end
76
+ end
77
+
78
+ # Trigger the callbacks (before, after, around)
79
+ # only if the document isn't new
80
+ def update(options = {})
81
+ run_callbacks :update do
82
+ run_callbacks :save do
83
+ # Check if record can be updated
84
+ raise "Cannot save a destroyed document!" if destroyed?
85
+ raise "Calling #{self.class.name}#update on document that has not been created!" if new?
86
+
87
+ # Check if we can continue
88
+ return false unless perform_validations(options)
89
+
90
+ # perform update
91
+ result = connection.update_node(self.id, self._to_database_hash)
92
+
93
+ # if something goes wrong we receive a nil value and return false
94
+ !result.nil?
95
+ end
96
+ end
97
+ end
98
+
99
+ def destroy
100
+ run_callbacks :destroy do
101
+ if result = connection.delete_node(self.id)
102
+ @_destroyed = true
103
+ self.freeze
104
+ end
105
+ result
106
+ end
107
+ end
108
+
109
+ def self.model_root_relation_type
110
+ 'model_root'
111
+ end
112
+
113
+ end
114
+
115
+ end
116
+
117
+ end
@@ -0,0 +1,95 @@
1
+ module Architect4r
2
+ module Model
3
+ module Persistency
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+
8
+ end
9
+
10
+ module InstanceMethods
11
+
12
+ # Creates the document in the db. Raises an exception
13
+ # if the document is not created properly.
14
+ def create!(options = {})
15
+ self.fail_validate!(self) unless self.create(options)
16
+ end
17
+
18
+ def save(options = {})
19
+ self.new? ? create(options) : update(options)
20
+ end
21
+
22
+ def save!
23
+ self.class.fail_validate!(self) unless self.save
24
+ true
25
+ end
26
+
27
+ def id
28
+ @id ||= if raw_data && raw_data['self'].present?
29
+ raw_data['self'].split('/').last.to_i
30
+ else
31
+ nil
32
+ end
33
+ end
34
+ alias :to_key :id
35
+ alias :to_param :id
36
+
37
+ def new?
38
+ # Persisted objects always have an id.
39
+ id.nil?
40
+ end
41
+ alias :new_record? :new?
42
+
43
+ def destroyed?
44
+ !!@_destroyed
45
+ end
46
+
47
+ def persisted?
48
+ !new? && !destroyed?
49
+ end
50
+
51
+ # Update the document's attributes and save. For example:
52
+ def update_attributes(hash)
53
+ update_attributes_without_saving hash
54
+ save
55
+ end
56
+
57
+ protected
58
+
59
+ def perform_validations(options = {})
60
+ (options[:validate].presence || true) ? valid? : true
61
+ end
62
+
63
+ end
64
+
65
+ module ClassMethods
66
+
67
+ def create(*args, &block)
68
+ instance = new(*args, &block)
69
+ instance.create
70
+ instance
71
+ end
72
+
73
+ # Defines an instance and save it directly to the database
74
+ def create!(*args, &block)
75
+ instance = new(*args, &block)
76
+ instance.create!
77
+ instance
78
+ end
79
+
80
+ protected
81
+
82
+ # Create an object from the database data
83
+ def build_from_database(data)
84
+ return nil if data.blank?
85
+
86
+ # Create an instance of the object
87
+ obj = self.new(data['data'])
88
+ obj.raw_data = data
89
+ obj
90
+ end
91
+
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,166 @@
1
+ module Architect4r
2
+
3
+ module Model
4
+
5
+ module Properties
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ class_attribute(:properties) unless respond_to?(:properties)
10
+ self.properties ||= {}
11
+ end
12
+
13
+ module InstanceMethods
14
+ def parse_properties(properties = {})
15
+ @properties_data = {}
16
+ update_attributes_without_saving(properties)
17
+ end
18
+
19
+ # Return a hash of all properties which can be transformed into json
20
+ # Remove all nil values, as those cannot be stored in the graph
21
+ def _to_database_hash
22
+ @properties_data.merge('architect4r_type' => self.class.name).
23
+ reject { |key, value| value.nil? }
24
+ end
25
+
26
+ # Read the casted value of an attribute defined with a property.
27
+ #
28
+ # ==== Returns
29
+ # Object:: the casted attibutes value.
30
+ def read_attribute(property, locale = nil)
31
+ property = "#{property}_#{locale}" if locale
32
+ @properties_data[property.to_s]
33
+ end
34
+
35
+ # Store a casted value in the current instance of an attribute defined
36
+ # with a property and update dirty status
37
+ def write_attribute(property, value, locale = nil)
38
+ # retrieve options for the attribute
39
+ opts = self.class.properties[property.to_s]
40
+
41
+ # Check if we should store a localized version of the data
42
+ property = "#{property}_#{locale}" if locale
43
+
44
+ # TODO: Mark dirty attribute tracking
45
+
46
+ # Cast the value before storing it
47
+ cast_to = opts && opts[:cast_to] || Object
48
+
49
+ @properties_data[property.to_s] = if value.nil?
50
+ nil
51
+ elsif cast_to == String
52
+ value.to_s
53
+ elsif cast_to == Integer
54
+ value.to_i
55
+ elsif cast_to == Float
56
+ value.to_f
57
+ elsif cast_to == TrueClass or cast_to == FalseClass
58
+ if value.kind_of?(Integer)
59
+ value == 1
60
+ else
61
+ %w[ true 1 t ].include?(value.to_s.downcase)
62
+ end
63
+ else
64
+ value
65
+ end
66
+ end
67
+
68
+ def update_attributes_without_saving(hash)
69
+ return if hash.nil?
70
+ hash.each do |key, value|
71
+ if self.respond_to?("#{key}=")
72
+ self.send("#{key}=", value)
73
+ else
74
+ @properties_data[key] = value
75
+ end
76
+ end
77
+ end
78
+ alias :attributes= :update_attributes_without_saving
79
+
80
+
81
+ end
82
+
83
+ module ClassMethods
84
+
85
+ # Allow setting properties
86
+ def property(name, options = {})
87
+ unless self.properties.keys.find { |p| p == name.to_s }
88
+ define_property(name, options)
89
+ end
90
+ end
91
+
92
+ def timestamps!
93
+ property(:updated_at, :cast_to => Time)
94
+ property(:created_at, :cast_to => Time)
95
+
96
+ set_callback :save, :before do |object|
97
+ write_attribute('updated_at', Time.now)
98
+ write_attribute('created_at', Time.now) if object.new?
99
+ end
100
+ end
101
+
102
+ protected
103
+
104
+ # This is not a thread safe operation, if you have to set new properties at runtime
105
+ # make sure a mutex is used.
106
+ def define_property(name, options={})
107
+ # read only flag
108
+ read_only = options.delete(:read_only) || false
109
+
110
+ # Store the property and its options
111
+ self.properties[name.to_s] = options
112
+
113
+ # Create getter and setter methods
114
+ create_property_getter(name)
115
+ create_property_setter(name) unless read_only == true
116
+
117
+ # Return property name just in case ;)
118
+ name
119
+ end
120
+
121
+ # defines the getter for the property (and optional aliases)
122
+ def create_property_getter(name)
123
+ define_method(name) do
124
+ # Get property configuration
125
+ localize = self.class.properties[name.to_s][:localize]
126
+
127
+ # Determine current locale
128
+ locale = localize ? I18n.locale : nil
129
+
130
+ # Fetch property value
131
+ result = read_attribute(name, locale)
132
+
133
+ # If there is a fallback locale, fetch its value if appropriate
134
+ if result.nil? && localize && localize != true && localize.to_s != locale.to_s
135
+ result = read_attribute(name, localize)
136
+ end
137
+
138
+ # Finally return some data
139
+ result
140
+ end
141
+
142
+ opts = self.properties[name.to_s]
143
+
144
+ if opts[:cast_to].presence && opts[:cast_to] == TrueClass
145
+ define_method("#{name}?") do
146
+ value = read_attribute(name)
147
+ !(value.nil? || value == false)
148
+ end
149
+ end
150
+ end
151
+
152
+ # defines the setter for the property (and optional aliases)
153
+ def create_property_setter(name)
154
+ define_method("#{name}=") do |value|
155
+ locale = self.class.properties[name.to_s][:localize] ? I18n.locale : nil
156
+ write_attribute(name, value, locale)
157
+ end
158
+ end
159
+
160
+ end
161
+
162
+ end
163
+
164
+ end
165
+
166
+ end