geoff 0.0.2.beta → 0.0.3.beta

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -16,3 +16,7 @@ tmp
16
16
  .yardoc
17
17
  _yardoc
18
18
  doc/
19
+ *.swp
20
+ *.swo
21
+ lib/jars
22
+ .DS_Store
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use jruby
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- geoff (0.2.4.beta)
4
+ geoff (0.0.3.beta)
5
5
  activesupport (~> 3.2.3)
6
6
  json
7
7
  neo4j
@@ -9,20 +9,20 @@ PATH
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- actionpack (3.2.6)
13
- activemodel (= 3.2.6)
14
- activesupport (= 3.2.6)
12
+ actionpack (3.2.8)
13
+ activemodel (= 3.2.8)
14
+ activesupport (= 3.2.8)
15
15
  builder (~> 3.0.0)
16
16
  erubis (~> 2.7.0)
17
- journey (~> 1.0.1)
17
+ journey (~> 1.0.4)
18
18
  rack (~> 1.4.0)
19
19
  rack-cache (~> 1.2)
20
20
  rack-test (~> 0.6.1)
21
21
  sprockets (~> 2.1.3)
22
- activemodel (3.2.6)
23
- activesupport (= 3.2.6)
22
+ activemodel (3.2.8)
23
+ activesupport (= 3.2.8)
24
24
  builder (~> 3.0.0)
25
- activesupport (3.2.6)
25
+ activesupport (3.2.8)
26
26
  i18n (~> 0.6)
27
27
  multi_json (~> 1.0)
28
28
  builder (3.0.0)
@@ -48,7 +48,7 @@ GEM
48
48
  neo4j-community (>= 1.7.0)
49
49
  neo4j-wrapper (2.0.1-java)
50
50
  neo4j-core (= 2.0.1)
51
- orm_adapter (0.3.0)
51
+ orm_adapter (0.4.0)
52
52
  pry (0.9.10)
53
53
  coderay (~> 1.0.5)
54
54
  method_source (~> 0.8)
@@ -65,9 +65,9 @@ GEM
65
65
  rack
66
66
  rack-test (0.6.1)
67
67
  rack (>= 1.0)
68
- railties (3.2.6)
69
- actionpack (= 3.2.6)
70
- activesupport (= 3.2.6)
68
+ railties (3.2.8)
69
+ actionpack (= 3.2.8)
70
+ activesupport (= 3.2.8)
71
71
  rack-ssl (~> 1.3.2)
72
72
  rake (>= 0.8.7)
73
73
  rdoc (~> 3.4)
data/README.md CHANGED
@@ -1,18 +1,39 @@
1
1
  geoff
2
2
  =====
3
3
 
4
- Ruby Geoff DSL
4
+ Geoff is "a declarative notation for representing graph data within concise
5
+ human-readable text, designed specifically with Neo4j in mind"
5
6
 
7
+ http://geoff.nigelsmall.net/
6
8
 
7
- Preview
8
- =======
9
+
10
+ This gem is a Ruby DSL for
11
+ * generating geoff syntax files
12
+ * batch inserting data into Neo4j
13
+
14
+ The reason for creating this gem is to:
15
+ * easily build data sets for tests
16
+ * that are readable and maintainable
17
+ * quickly batch insert the whole data set in one transaction
18
+
19
+ Prerequesites/ Caveats
20
+ ---------------------
21
+ * A ruby project
22
+ * Gemfile with `gem 'geoff', '0.0.2.beta'`
23
+ * neo4j jar and geoff jar files in lib/jars (not included, but required!)
24
+ * Current implementation assumes usage of the neo4j wrapper gem
25
+ * Neo4j::Rails::Model classes or a class that includes the Neo4j::NodeMixin
26
+
27
+ Usage
28
+ -------
9
29
 
10
30
 
11
31
  ```ruby
12
32
 
13
33
  #Basic tree like structure for DSL
14
34
  #the first line generates the class nodes used by Neo4jWrapper
15
- Geoff(Company, Person) do
35
+
36
+ Geoff(Company, Person) do # NB 'Company' and 'Person' are classes with the Neo4j::NodeMixin
16
37
  company 'Acme' do
17
38
  address "13 Something Road"
18
39
 
@@ -38,6 +59,31 @@ end
38
59
 
39
60
  ```
40
61
 
62
+
63
+ ###Using a ramdisk see http://neo4j.rubyforge.org/guides/configuration.html
64
+
65
+ ```sh
66
+ diskutil erasevolume HFS+ "ramdisk" `hdiutil attach -nomount ram://1165430`
67
+ ```
68
+
69
+ ```ruby
70
+
71
+ #in spec helper
72
+ Neo4j::Config[:storage_path] = '/Volumes/ramdisk'
73
+
74
+ #in rspec
75
+ before do
76
+ geoff = Geoff(Company) do
77
+ company 'Acme' do
78
+ address "13 Something Road"
79
+ end
80
+ end
81
+
82
+ #Don't display output, and delete existing database
83
+ Geoff::Importer.import geoff, silent: false, delete: true
84
+ end
85
+
86
+
41
87
  ```
42
88
  (ROOT)-[:Company]->(Company)
43
89
  (ROOT)-[:Person]->(Person)
@@ -122,7 +168,7 @@ end
122
168
  ```
123
169
 
124
170
 
125
- #Using the outer bindings scope
171
+ #Using the outer scope
126
172
  ```ruby
127
173
  @hours = SomeFancyAttributeParser.parse <<-EOF
128
174
  Monday 09:00-15:00
@@ -131,7 +177,7 @@ Saturday 09:00-16:00
131
177
  Sunday closed
132
178
  EOF
133
179
 
134
- Geoff(Company, binding: binding) do
180
+ Geoff(Company, target: self) do
135
181
  company 'Amazon' do
136
182
  opening_hours ->{ @hours }
137
183
  end
data/lib/geoff.rb CHANGED
@@ -10,3 +10,4 @@ end
10
10
 
11
11
  class Geoff::Error < StandardError; end
12
12
  class Geoff::MissingNodeDefinition < Geoff::Error ; end
13
+ class Geoff::DslSyntaxError < Geoff::Error; end
@@ -1,19 +1,23 @@
1
1
  require 'geoff/node_dsl'
2
2
  require 'geoff/container'
3
+ require 'geoff/dsl_exception_handling'
3
4
  require 'active_support/core_ext/string'
4
5
 
5
6
  class ChildrenDsl
7
+ include DslExceptionHandling
8
+
6
9
  def initialize options, &block
7
10
  @parent_node_name = options[:parent_node_name]
8
11
  @parent_rel_type = options[:type]
9
- @outer_binding = options[:binding]
12
+ @target = options[:target]
10
13
  @outer_geoff = options[:geoff]
11
14
 
12
15
  @write_mode = false
13
16
 
14
17
  @node_dsls = {}
15
18
  @container = options[:container] || Container.new
16
- write_mode { instance_eval(&block) }
19
+
20
+ eval_with_exceptions(&block)
17
21
  end
18
22
 
19
23
  def to_geoff
@@ -51,14 +55,6 @@ class ChildrenDsl
51
55
 
52
56
  private
53
57
 
54
- #prevent very confusing method_missing calls during debugging by
55
- #only writing to the object when expected
56
- def write_mode
57
- @write_mode = true
58
- yield
59
- @write_mode = false
60
- end
61
-
62
58
  # e.g.
63
59
  #company "ACME" do
64
60
  # children "works_at" do
@@ -72,7 +68,7 @@ class ChildrenDsl
72
68
  return super unless @write_mode
73
69
  relationship, options = parse_method_missing m, *args
74
70
 
75
- options.merge!(binding: @outer_binding)
71
+ options.merge!(target: @target)
76
72
  NodeDsl.new(options, &blk).tap do |n|
77
73
  @node_dsls[n] = relationship
78
74
  end
@@ -0,0 +1,52 @@
1
+ module DslExceptionHandling
2
+ #prevent very confusing method_missing calls during debugging by
3
+ #only writing to the object when expected
4
+ def write_mode
5
+ @write_mode = true
6
+ yield
7
+ @write_mode = false
8
+ end
9
+
10
+ def eval_with_exceptions &block
11
+ write_mode do
12
+ begin
13
+ instance_eval(&block)
14
+
15
+ rescue Exception => e
16
+ #don't swallow exceptions further down the tree
17
+ raise e if e.is_a? Geoff::DslSyntaxError
18
+
19
+ lines = caller.select{|c| (c !~ /geoff\/lib\/geoff/)and (c !~ /ruby-debug/) }
20
+
21
+ file, number, method = lines.first.split ":"
22
+ message = "Syntax Error in #{method} in Geoff DSL block for:\n#{file}:#{number}\n"
23
+
24
+ message << lines_around(file, number) do |m|
25
+ "\n\n#{e.message}\n\n"
26
+ end
27
+
28
+ raise Geoff::DslSyntaxError, message
29
+ end
30
+
31
+ end
32
+ end
33
+
34
+ def lines_around file, number, context = 10
35
+ number = number.to_i
36
+ range = (number - context) .. (number + context)
37
+ lines = File.read(file).split("\n")
38
+
39
+ filtered_lines = range.inject({}) do |l, i|
40
+ l[i] = lines[i]
41
+ l
42
+ end
43
+
44
+ filtered_lines.map do |line_number, line|
45
+ if line_number == number
46
+ yield + ">#{line_number} #{line}"
47
+ else
48
+ " #{line_number} #{line}"
49
+ end
50
+ end.join "\n"
51
+ end
52
+ end
@@ -3,12 +3,19 @@ require 'fileutils'
3
3
  Dir["lib/jars/*"].each {|file| require file }
4
4
 
5
5
  module Geoff
6
- class MissingIndexedProperty < StandardError; end
6
+ class Error < StandardError ; end
7
+ class MissingIndexedProperty < Geoff::Error ; end
8
+ class InvalidRules < Geoff::Error ; end
9
+
10
+ def self.import *args
11
+ Importer.import *args
12
+ end
7
13
 
8
14
  class Importer
9
- class << self
15
+ Subgraph = org.neo4j.geoff.Subgraph
10
16
 
11
- def import_files *files, options
17
+ class << self
18
+ def import_files(*files, options)
12
19
  concatenated = files.map{|f|File.read f}.join "\n"
13
20
 
14
21
  import concatenated, options
@@ -20,10 +27,6 @@ module Geoff
20
27
  end
21
28
 
22
29
  def import(geoff, options = {})
23
- db_path = options[:test] ? 'db/test' : 'db/development'
24
-
25
- Neo4j::Config[:storage_path] = db_path
26
-
27
30
  geoff = geoff.to_geoff unless geoff.is_a? String
28
31
 
29
32
  geoff = geoff.split "\n" if geoff.is_a? String
@@ -39,7 +42,7 @@ module Geoff
39
42
  end
40
43
 
41
44
  def go
42
- raise 'Invalid rules' unless validate_rules(@rules)
45
+ raise Geoff::InvalidRules.new('Invalid rules') unless validate_rules(@rules)
43
46
  delete_database if drop?
44
47
 
45
48
  log 'importing the database'
@@ -68,7 +71,7 @@ module Geoff
68
71
  end
69
72
 
70
73
  def import_geoff_rules(rules)
71
- sub_graph = org.neo4j.geoff.Subgraph.new(rules)
74
+ sub_graph = Subgraph.new(rules)
72
75
  node_map = { '0' => root_node }
73
76
  org.neo4j.geoff.Geoff.insertIntoNeo4j(sub_graph, Neo4j.db.graph, node_map );
74
77
  end
@@ -101,12 +104,12 @@ module Geoff
101
104
 
102
105
  rescue NativeException => e
103
106
  log "-" * 80
104
- message = "Exception during re-indexing #{type} with #{@current_node} and index #{@current_index}"
107
+ message = "#{type} missing indexed attribute #{@current_index}, on node: #{@current_node.attributes}"
105
108
  log message
106
109
  log "-" * 80
107
110
  log e.message
108
111
  log "-" * 80
109
- #raise Geoff::MissingIndexedProperty, message
112
+ raise Geoff::MissingIndexedProperty, message
110
113
  end
111
114
 
112
115
  def tx
@@ -138,16 +141,19 @@ module Geoff
138
141
  end
139
142
 
140
143
  def validate_rules(rules)
141
- invalid = Array(rules).reject{ |r| validate_rule(r) }
142
- invalid.each { |r| log "Rule '#{r}' is invalid" }
143
- invalid.empty?
144
+ @invalid = Array(rules).map do |r|
145
+ validate_rule(r)
146
+ end.compact
147
+
148
+ @invalid.each { |r, message| log "Rule '#{r}' is invalid: #{message}" }
149
+ @invalid.empty?
144
150
  end
145
151
 
146
152
  def validate_rule(rule)
147
- org.neo4j.geoff.Subgraph.new(Array(rule))
148
- true
149
- rescue
150
- false
153
+ Subgraph.new(Array(rule))
154
+ nil
155
+ rescue Exception => e
156
+ return [rule, e.message]
151
157
  end
152
158
 
153
159
  end
@@ -21,6 +21,10 @@ class Neo4jWrapperDsl
21
21
  geoff.chomp
22
22
  end
23
23
 
24
+ def <=> other
25
+ to_geoff == other.to_geoff ? 0 : -1
26
+ end
27
+
24
28
  def to_s
25
29
  to_geoff
26
30
  end
@@ -1,6 +1,9 @@
1
1
  require 'geoff/children_dsl'
2
+ require 'geoff/dsl_exception_handling'
2
3
 
3
4
  class NodeDsl
5
+ include DslExceptionHandling
6
+
4
7
  attr_reader :node_name
5
8
 
6
9
  def initialize(options, &block)
@@ -8,19 +11,20 @@ class NodeDsl
8
11
  @klass_name = options[:klass_name] || 'ROOT'
9
12
  @container = options[:container] || Container.new
10
13
  @rel_type = options[:rel_type]
11
- @outer_binding = options[:binding]
14
+ @target = options[:target]
12
15
  @properties = {}
13
16
  @children_dsls = []
14
17
 
15
18
  @rendered = false
16
19
 
17
- write_mode { instance_eval(&block) } if block_given?
20
+ eval_with_exceptions(&block) if block_given?
18
21
  end
19
22
 
20
23
  def to_geoff
21
24
  geoff_lines.join "\n"
22
25
  end
23
26
 
27
+
24
28
  def geoff_lines
25
29
  #we need this to prevent rendering same node which is rendered already
26
30
  return [] if @rendered
@@ -59,14 +63,6 @@ class NodeDsl
59
63
  end
60
64
  end
61
65
 
62
- #prevent very confusing method_missing calls during debugging by
63
- #only writing to the object when expected
64
- def write_mode
65
- @write_mode = true
66
- yield
67
- @write_mode = false
68
- end
69
-
70
66
  # e.g.
71
67
  #sandwich "BLT", type: :on_menu do
72
68
  # filling 'bacon'
@@ -80,7 +76,7 @@ class NodeDsl
80
76
  else
81
77
  return super unless @write_mode
82
78
  val = if args.first.is_a? Proc
83
- eval("@#{m}", @outer_binding)
79
+ @target.instance_exec &args.first
84
80
  else
85
81
  args.first
86
82
  end
@@ -94,13 +90,13 @@ class NodeDsl
94
90
 
95
91
  private
96
92
 
97
- def children type=nil, &block
98
- options = {
93
+ def children type=nil, options={}, &block
94
+ options.merge!({
99
95
  parent_node_name: @node_name,
100
96
  type: type,
101
97
  container: @container,
102
- binding: @outer_binding
103
- }
98
+ target: @target
99
+ })
104
100
 
105
101
  @children_dsls << ChildrenDsl.new(options, &block)
106
102
  end
data/lib/geoff/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Geoff
2
- VERSION = "0.0.2.beta"
2
+ VERSION = "0.0.3.beta"
3
3
  end
@@ -38,9 +38,9 @@ describe ChildrenDsl do
38
38
  let(:top) {ChildrenDsl.new(parent_node_name: 'starbucks', type: :x ){area 'Luton' } }
39
39
  let(:on_node){ChildrenDsl.new(parent_node_name: 'starbucks') {area 'Luton', type: :x }}
40
40
 
41
- specify { ->{missing }.should raise_error ArgumentError}
42
- specify { ->{ top }.should_not raise_error ArgumentError }
43
- specify { ->{ on_node}.should_not raise_error ArgumentError }
41
+ specify { ->{missing }.should raise_error Geoff::DslSyntaxError}
42
+ specify { ->{ top }.should_not raise_error }
43
+ specify { ->{ on_node}.should_not raise_error }
44
44
  end
45
45
 
46
46
  describe 'with special node' do
@@ -58,20 +58,20 @@ describe NodeDsl do
58
58
  strip_whitespace <<-EOS
59
59
  (starbucks) {"_classname":"Cafe"}
60
60
  (Cafe)-[:all]->(starbucks)
61
- (starbucks_branch_1) {"_classname":"Branch","delay_time":15,"hours":"3"}
61
+ (starbucks_branch_1) {"_classname":"Branch","delay_time":15,"opening_hours":3}
62
62
  (Branch)-[:all]->(starbucks_branch_1)
63
63
  (starbucks)-[:owns]->(starbucks_branch_1) {"some":"property"}
64
64
  EOS
65
65
  end
66
66
 
67
67
  specify do
68
- @hours = "3"
68
+ @hours = 3
69
69
 
70
- node = NodeDsl.new(node_name: 'starbucks', klass_name: 'Cafe', binding: binding) do
70
+ node = NodeDsl.new(node_name: 'starbucks', klass_name: 'Cafe', target: self) do
71
71
  children do
72
72
  branch 'starbucks_branch_1', type: 'owns', some: 'property' do
73
73
  delay_time 15
74
- hours ->{@hours}
74
+ opening_hours ->{@hours}
75
75
  end
76
76
  end
77
77
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: geoff
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: 6
5
- version: 0.0.2.beta
5
+ version: 0.0.3.beta
6
6
  platform: ruby
7
7
  authors:
8
8
  - David Rouchy
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2012-08-10 00:00:00.000000000 Z
16
+ date: 2012-08-15 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: neo4j
@@ -123,6 +123,7 @@ extensions: []
123
123
  extra_rdoc_files: []
124
124
  files:
125
125
  - .gitignore
126
+ - .rvmrc
126
127
  - Gemfile
127
128
  - Gemfile.lock
128
129
  - LICENSE
@@ -132,6 +133,7 @@ files:
132
133
  - lib/geoff.rb
133
134
  - lib/geoff/children_dsl.rb
134
135
  - lib/geoff/container.rb
136
+ - lib/geoff/dsl_exception_handling.rb
135
137
  - lib/geoff/importer.rb
136
138
  - lib/geoff/neo4j_wrapper_dsl.rb
137
139
  - lib/geoff/neo4j_wrapper_validator.rb